diff options
Diffstat (limited to 'indra')
-rw-r--r-- | indra/llcommon/llprocesslauncher.cpp | 24 | ||||
-rw-r--r-- | indra/llplugin/llpluginclassmedia.cpp | 16 | ||||
-rw-r--r-- | indra/llplugin/llpluginclassmedia.h | 5 | ||||
-rw-r--r-- | indra/llplugin/llpluginclassmediaowner.h | 3 | ||||
-rw-r--r-- | indra/media_plugins/webkit/media_plugin_webkit.cpp | 18 | ||||
-rw-r--r-- | indra/newview/app_settings/settings.xml | 11 | ||||
-rw-r--r-- | indra/newview/llfloaterwebcontent.cpp | 6 | ||||
-rw-r--r-- | indra/newview/llhudeffectblob.cpp | 30 | ||||
-rw-r--r-- | indra/newview/llhudeffectblob.h | 2 | ||||
-rw-r--r-- | indra/newview/llmediactrl.cpp | 22 | ||||
-rw-r--r-- | indra/newview/llmediactrl.h | 4 | ||||
-rw-r--r-- | indra/newview/llstartup.cpp | 6456 | ||||
-rw-r--r-- | indra/newview/lltoolpie.cpp | 143 | ||||
-rw-r--r-- | indra/newview/lltoolpie.h | 3 | ||||
-rw-r--r-- | indra/newview/llviewermenu.cpp | 16372 | ||||
-rw-r--r-- | indra/newview/llviewermessage.cpp | 13816 | ||||
-rw-r--r-- | indra/newview/llviewerparcelmedia.cpp | 6 | ||||
-rw-r--r-- | indra/newview/llviewerwindow.cpp | 10074 | ||||
-rw-r--r-- | indra/newview/skins/default/textures/textures.xml | 1 | ||||
-rw-r--r-- | indra/newview/skins/default/textures/world/CameraDragDot.png | bin | 0 -> 3101 bytes |
20 files changed, 23546 insertions, 23466 deletions
diff --git a/indra/llcommon/llprocesslauncher.cpp b/indra/llcommon/llprocesslauncher.cpp index d46188104f..10950181fd 100644 --- a/indra/llcommon/llprocesslauncher.cpp +++ b/indra/llcommon/llprocesslauncher.cpp @@ -103,10 +103,30 @@ int LLProcessLauncher::launch(void) char *args2 = new char[args.size() + 1]; strcpy(args2, args.c_str()); - if( ! CreateProcessA( NULL, args2, NULL, NULL, FALSE, 0, NULL, mWorkingDir.c_str(), &sinfo, &pinfo ) ) + const char * working_directory = 0; + if(!mWorkingDir.empty()) working_directory = mWorkingDir.c_str(); + if( ! CreateProcessA( NULL, args2, NULL, NULL, FALSE, 0, NULL, working_directory, &sinfo, &pinfo ) ) { - // TODO: do better than returning the OS-specific error code on failure... result = GetLastError(); + + LPTSTR error_str = 0; + if( + FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + result, + 0, + (LPTSTR)&error_str, + 0, + NULL) + != 0) + { + char message[256]; + wcstombs(message, error_str, 256); + message[255] = 0; + llwarns << "CreateProcessA failed: " << message << llendl; + LocalFree(error_str); + } + if(result == 0) { // Make absolutely certain we return a non-zero value on failure. diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 26a20cede8..57f91a57ca 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -146,6 +146,7 @@ void LLPluginClassMedia::reset() mClickURL.clear(); mClickTarget.clear(); mClickUUID.clear(); + mStatusCode = 0; // media_time class mCurrentTime = 0.0f; @@ -1027,6 +1028,11 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) mClickTarget.clear(); mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_NOFOLLOW); } + else if(message_name == "navigate_error_page") + { + mStatusCode = message.getValueS32("status_code"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_ERROR_PAGE); + } else if(message_name == "cookie_set") { if(mOwner) @@ -1192,16 +1198,6 @@ void LLPluginClassMedia::browse_back() sendMessage(message); } -void LLPluginClassMedia::set_status_redirect(int code, const std::string &url) -{ - LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_status_redirect"); - - message.setValueS32("code", code); - message.setValue("url", url); - - sendMessage(message); -} - void LLPluginClassMedia::setBrowserUserAgent(const std::string& user_agent) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_user_agent"); diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index 618e928a08..a940633b88 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -199,7 +199,6 @@ public: void browse_reload(bool ignore_cache = false); void browse_forward(); void browse_back(); - void set_status_redirect(int code, const std::string &url); void setBrowserUserAgent(const std::string& user_agent); void proxyWindowOpened(const std::string &target, const std::string &uuid); void proxyWindowClosed(const std::string &uuid); @@ -232,6 +231,9 @@ public: // This is valid during MEDIA_EVENT_CLICK_LINK_HREF and MEDIA_EVENT_GEOMETRY_CHANGE std::string getClickUUID() const { return mClickUUID; }; + + // This is valid after MEDIA_EVENT_NAVIGATE_ERROR_PAGE + S32 getStatusCode() const { return mStatusCode; }; // These are valid during MEDIA_EVENT_GEOMETRY_CHANGE S32 getGeometryX() const { return mGeometryX; }; @@ -384,6 +386,7 @@ protected: S32 mGeometryY; S32 mGeometryWidth; S32 mGeometryHeight; + S32 mStatusCode; std::string mAuthURL; std::string mAuthRealm; std::string mHoverText; diff --git a/indra/llplugin/llpluginclassmediaowner.h b/indra/llplugin/llpluginclassmediaowner.h index 42e93cc6d7..5a4fb1ce90 100644 --- a/indra/llplugin/llpluginclassmediaowner.h +++ b/indra/llplugin/llpluginclassmediaowner.h @@ -52,12 +52,13 @@ public: MEDIA_EVENT_STATUS_TEXT_CHANGED, // browser has updated the status text MEDIA_EVENT_NAME_CHANGED, // browser has updated the name of the media (typically <title> tag) MEDIA_EVENT_LOCATION_CHANGED, // browser location (URL) has changed (maybe due to internal navagation/frames/etc) + MEDIA_EVENT_NAVIGATE_ERROR_PAGE, // browser navigated to a page that resulted in an HTTP error MEDIA_EVENT_CLICK_LINK_HREF, // I'm not entirely sure what the semantics of these two are MEDIA_EVENT_CLICK_LINK_NOFOLLOW, MEDIA_EVENT_CLOSE_REQUEST, // The plugin requested its window be closed (currently hooked up to javascript window.close in webkit) MEDIA_EVENT_PICK_FILE_REQUEST, // The plugin wants the user to pick a file MEDIA_EVENT_GEOMETRY_CHANGE, // The plugin requested its window geometry be changed (per the javascript window interface) - + MEDIA_EVENT_PLUGIN_FAILED_LAUNCH, // The plugin failed to launch MEDIA_EVENT_PLUGIN_FAILED, // The plugin died unexpectedly diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp index d6f8ae3e16..c1bc9adec0 100644 --- a/indra/media_plugins/webkit/media_plugin_webkit.cpp +++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp @@ -492,6 +492,15 @@ private: //////////////////////////////////////////////////////////////////////////////// // virtual + void onNavigateErrorPage(const EventType& event) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_error_page"); + message.setValueS32("status_code", event.getIntValue()); + sendMessage(message); + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual void onLocationChange(const EventType& event) { if(mInitState >= INIT_STATE_NAVIGATE_COMPLETE) @@ -1225,15 +1234,6 @@ void MediaPluginWebKit::receiveMessage(const char *message_string) { LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK ); } - else if(message_name == "set_status_redirect") - { - int code = message_in.getValueS32("code"); - std::string url = message_in.getValue("url"); - if ( 404 == code ) // browser lib only supports 404 right now - { - LLQtWebKit::getInstance()->set404RedirectUrl( mBrowserWindowId, url ); - }; - } else if(message_name == "set_user_agent") { mUserAgent = message_in.getValue("user_agent"); diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 6a89f5681d..c626538808 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -12586,5 +12586,16 @@ <key>Value</key> <integer>1</integer> </map> + <key>WebContentFloaterErrorURL</key> + <map> + <key>Comment</key> + <string>URL to navigate to if the Web content floater hits a page with a 400-499 HTTP status code</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>String</string> + <key>Value</key> + <string>http://common-flash-secondlife-com.s3.amazonaws.com/viewer/v2.6/damballah/404.html</string> + </map> </map> </llsd> diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp index 058567492b..76fb985b39 100644 --- a/indra/newview/llfloaterwebcontent.cpp +++ b/indra/newview/llfloaterwebcontent.cpp @@ -328,6 +328,12 @@ void LLFloaterWebContent::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent const std::string link = self->getHoverLink(); mStatusBarText->setText( link ); } + else if(event == MEDIA_EVENT_NAVIGATE_ERROR_PAGE ) + { + std::string redirect_url = gSavedSettings.getString("WebContentFloaterErrorURL"); + mWebBrowser->navigateTo(redirect_url, "text/html"); + set_current_url(redirect_url); + } } void LLFloaterWebContent::set_current_url(const std::string& url) diff --git a/indra/newview/llhudeffectblob.cpp b/indra/newview/llhudeffectblob.cpp index 26e8251899..d8687eed8d 100644 --- a/indra/newview/llhudeffectblob.cpp +++ b/indra/newview/llhudeffectblob.cpp @@ -30,13 +30,14 @@ #include "llagent.h" #include "llviewercamera.h" -#include "llrendersphere.h" +#include "llui.h" LLHUDEffectBlob::LLHUDEffectBlob(const U8 type) : LLHUDEffect(type), mPixelSize(10) { mTimer.start(); + mImage = LLUI::getUIImage("Camera_Drag_Dot"); } LLHUDEffectBlob::~LLHUDEffectBlob() @@ -58,18 +59,29 @@ void LLHUDEffectBlob::render() LLViewerCamera::instance().getPixelVectors(pos_agent, pixel_up, pixel_right); LLGLSPipelineAlpha gls_pipeline_alpha; - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(0)->bind(mImage->getImage()); LLColor4U color = mColor; color.mV[VALPHA] = (U8)clamp_rescale(time, 0.f, mDuration, 255.f, 0.f); - glColor4ubv(color.mV); + gGL.color4ubv(color.mV); - glPushMatrix(); - glTranslatef(pos_agent.mV[0], pos_agent.mV[1], pos_agent.mV[2]); - F32 scale = pixel_up.magVec() * (F32)mPixelSize; - glScalef(scale, scale, scale); - gSphere.render(0); - glPopMatrix(); + { gGL.pushMatrix(); + gGL.translatef(pos_agent.mV[0], pos_agent.mV[1], pos_agent.mV[2]); + LLVector3 u_scale = pixel_right * (F32)mPixelSize; + LLVector3 v_scale = pixel_up * (F32)mPixelSize; + + { gGL.begin(LLRender::QUADS); + gGL.texCoord2f(0.f, 1.f); + gGL.vertex3fv((v_scale - u_scale).mV); + gGL.texCoord2f(0.f, 0.f); + gGL.vertex3fv((-v_scale - u_scale).mV); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex3fv((-v_scale + u_scale).mV); + gGL.texCoord2f(1.f, 1.f); + gGL.vertex3fv((v_scale + u_scale).mV); + } gGL.end(); + + } gGL.popMatrix(); } void LLHUDEffectBlob::renderForTimer() diff --git a/indra/newview/llhudeffectblob.h b/indra/newview/llhudeffectblob.h index 5b0703cdaa..f4c1691108 100644 --- a/indra/newview/llhudeffectblob.h +++ b/indra/newview/llhudeffectblob.h @@ -28,6 +28,7 @@ #define LL_LLHUDEFFECTBLOB_H #include "llhudeffect.h" +#include "lluiimage.h" class LLHUDEffectBlob : public LLHUDEffect { @@ -45,6 +46,7 @@ protected: private: S32 mPixelSize; LLFrameTimer mTimer; + LLPointer<LLUIImage> mImage; }; #endif // LL_LLHUDEFFECTBLOB_H diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index 9493fddf50..376e38ade3 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -503,22 +503,6 @@ bool LLMediaCtrl::canNavigateForward() //////////////////////////////////////////////////////////////////////////////// // -void LLMediaCtrl::set404RedirectUrl( std::string redirect_url ) -{ - if(mMediaSource && mMediaSource->hasMedia()) - mMediaSource->getMediaPlugin()->set_status_redirect( 404, redirect_url ); -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLMediaCtrl::clr404RedirectUrl() -{ - if(mMediaSource && mMediaSource->hasMedia()) - mMediaSource->getMediaPlugin()->set_status_redirect(404, ""); -} - -//////////////////////////////////////////////////////////////////////////////// -// void LLMediaCtrl::clearCache() { if(mMediaSource) @@ -976,6 +960,12 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) }; break; + case MEDIA_EVENT_NAVIGATE_ERROR_PAGE: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_ERROR_PAGE" << LL_ENDL; + }; + break; + case MEDIA_EVENT_CLICK_LINK_HREF: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << self->getClickTarget() << "\", uri is " << self->getClickURL() << LL_ENDL; diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index 38a74f90d3..7a28b0986d 100644 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -113,10 +113,6 @@ public: void setTarget(const std::string& target); - // set/clear URL to visit when a 404 page is reached - void set404RedirectUrl( std::string redirect_url ); - void clr404RedirectUrl(); - // Clear the browser cache when the instance gets loaded void clearCache(); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 45159de66e..8fccb35886 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1,3229 +1,3227 @@ -/**
- * @file llstartup.cpp
- * @brief startup routines.
- *
- * $LicenseInfo:firstyear=2004&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llstartup.h"
-
-#if LL_WINDOWS
-# include <process.h> // _spawnl()
-#else
-# include <sys/stat.h> // mkdir()
-#endif
-
-#include "llviewermedia_streamingaudio.h"
-#include "llaudioengine.h"
-
-#ifdef LL_FMOD
-# include "llaudioengine_fmod.h"
-#endif
-
-#ifdef LL_OPENAL
-#include "llaudioengine_openal.h"
-#endif
-
-#include "llares.h"
-#include "llavatarnamecache.h"
-#include "lllandmark.h"
-#include "llcachename.h"
-#include "lldir.h"
-#include "llerrorcontrol.h"
-#include "llfloaterreg.h"
-#include "llfocusmgr.h"
-#include "llhttpsender.h"
-#include "llimfloater.h"
-#include "lllocationhistory.h"
-#include "llimageworker.h"
-
-#include "llloginflags.h"
-#include "llmd5.h"
-#include "llmemorystream.h"
-#include "llmessageconfig.h"
-#include "llmoveview.h"
-#include "llnearbychat.h"
-#include "llnotifications.h"
-#include "llnotificationsutil.h"
-#include "llteleporthistory.h"
-#include "llregionhandle.h"
-#include "llsd.h"
-#include "llsdserialize.h"
-#include "llsdutil_math.h"
-#include "llsecondlifeurls.h"
-#include "llstring.h"
-#include "lluserrelations.h"
-#include "llversioninfo.h"
-#include "llviewercontrol.h"
-#include "llvfs.h"
-#include "llxorcipher.h" // saved password, MAC address
-#include "llwindow.h"
-#include "imageids.h"
-#include "message.h"
-#include "v3math.h"
-
-#include "llagent.h"
-#include "llagentcamera.h"
-#include "llagentpicksinfo.h"
-#include "llagentwearables.h"
-#include "llagentpilot.h"
-#include "llfloateravatarpicker.h"
-#include "llcallbacklist.h"
-#include "llcallingcard.h"
-#include "llconsole.h"
-#include "llcontainerview.h"
-#include "lldebugview.h"
-#include "lldrawable.h"
-#include "lleventnotifier.h"
-#include "llface.h"
-#include "llfeaturemanager.h"
-//#include "llfirstuse.h"
-#include "llfloaterhud.h"
-#include "llfloaterland.h"
-#include "llfloaterpreference.h"
-#include "llfloatertopobjects.h"
-#include "llfloaterworldmap.h"
-#include "llgesturemgr.h"
-#include "llgroupmgr.h"
-#include "llhudeffecttrail.h"
-#include "llhudmanager.h"
-#include "llhttpclient.h"
-#include "llimagebmp.h"
-#include "llinventorybridge.h"
-#include "llinventorymodel.h"
-#include "llinventorymodelbackgroundfetch.h"
-#include "llkeyboard.h"
-#include "llloginhandler.h" // gLoginHandler, SLURL support
-#include "lllogininstance.h" // Host the login module.
-#include "llpanellogin.h"
-#include "llmutelist.h"
-#include "llavatarpropertiesprocessor.h"
-#include "llpanelclassified.h"
-#include "llpanelpick.h"
-#include "llpanelgrouplandmoney.h"
-#include "llpanelgroupnotices.h"
-#include "llpreview.h"
-#include "llpreviewscript.h"
-#include "llproductinforequest.h"
-#include "llsecondlifeurls.h"
-#include "llselectmgr.h"
-#include "llsky.h"
-#include "llsidetray.h"
-#include "llstatview.h"
-#include "llstatusbar.h" // sendMoneyBalanceRequest(), owns L$ balance
-#include "llsurface.h"
-#include "lltexturecache.h"
-#include "lltexturefetch.h"
-#include "lltoolmgr.h"
-#include "lltrans.h"
-#include "llui.h"
-#include "llurldispatcher.h"
-#include "llurlentry.h"
-#include "llslurl.h"
-#include "llurlhistory.h"
-#include "llurlwhitelist.h"
-#include "llvieweraudio.h"
-#include "llviewerassetstorage.h"
-#include "llviewercamera.h"
-#include "llviewerdisplay.h"
-#include "llviewergenericmessage.h"
-#include "llviewergesture.h"
-#include "llviewertexturelist.h"
-#include "llviewermedia.h"
-#include "llviewermenu.h"
-#include "llviewermessage.h"
-#include "llviewernetwork.h"
-#include "llviewerobjectlist.h"
-#include "llviewerparcelmedia.h"
-#include "llviewerparcelmgr.h"
-#include "llviewerregion.h"
-#include "llviewerstats.h"
-#include "llviewerthrottle.h"
-#include "llviewerwindow.h"
-#include "llvoavatar.h"
-#include "llvoavatarself.h"
-#include "llvoclouds.h"
-#include "llweb.h"
-#include "llworld.h"
-#include "llworldmapmessage.h"
-#include "llxfermanager.h"
-#include "pipeline.h"
-#include "llappviewer.h"
-#include "llfasttimerview.h"
-#include "llfloatermap.h"
-#include "llweb.h"
-#include "llvoiceclient.h"
-#include "llnamelistctrl.h"
-#include "llnamebox.h"
-#include "llnameeditor.h"
-#include "llpostprocess.h"
-#include "llwlparammanager.h"
-#include "llwaterparammanager.h"
-#include "llagentlanguage.h"
-#include "llwearable.h"
-#include "llinventorybridge.h"
-#include "llappearancemgr.h"
-#include "llavatariconctrl.h"
-#include "llvoicechannel.h"
-
-#include "lllogin.h"
-#include "llevents.h"
-#include "llstartuplistener.h"
-
-#if LL_WINDOWS
-#include "lldxhardware.h"
-#endif
-
-//
-// exported globals
-//
-bool gAgentMovementCompleted = false;
-S32 gMaxAgentGroups;
-
-std::string SCREEN_HOME_FILENAME = "screen_home.bmp";
-std::string SCREEN_LAST_FILENAME = "screen_last.bmp";
-
-LLPointer<LLViewerTexture> gStartTexture;
-
-//
-// Imported globals
-//
-extern S32 gStartImageWidth;
-extern S32 gStartImageHeight;
-
-//
-// local globals
-//
-static bool gGotUseCircuitCodeAck = false;
-static std::string sInitialOutfit;
-static std::string sInitialOutfitGender; // "male" or "female"
-static boost::signals2::connection sWearablesLoadedCon;
-
-static bool gUseCircuitCallbackCalled = false;
-
-EStartupState LLStartUp::gStartupState = STATE_FIRST;
-LLSLURL LLStartUp::sStartSLURL;
-
-static LLPointer<LLCredential> gUserCredential;
-static std::string gDisplayName;
-static BOOL gRememberPassword = TRUE;
-
-static U64 gFirstSimHandle = 0;
-static LLHost gFirstSim;
-static std::string gFirstSimSeedCap;
-static LLVector3 gAgentStartLookAt(1.0f, 0.f, 0.f);
-static std::string gAgentStartLocation = "safe";
-static bool mLoginStatePastUI = false;
-
-
-boost::scoped_ptr<LLEventPump> LLStartUp::sStateWatcher(new LLEventStream("StartupState"));
-boost::scoped_ptr<LLStartupListener> LLStartUp::sListener(new LLStartupListener());
-
-//
-// local function declaration
-//
-
-void login_show();
-void login_callback(S32 option, void* userdata);
-void show_first_run_dialog();
-bool first_run_dialog_callback(const LLSD& notification, const LLSD& response);
-void set_startup_status(const F32 frac, const std::string& string, const std::string& msg);
-bool login_alert_status(const LLSD& notification, const LLSD& response);
-void login_packet_failed(void**, S32 result);
-void use_circuit_callback(void**, S32 result);
-void register_viewer_callbacks(LLMessageSystem* msg);
-void asset_callback_nothing(LLVFS*, const LLUUID&, LLAssetType::EType, void*, S32);
-bool callback_choose_gender(const LLSD& notification, const LLSD& response);
-void init_start_screen(S32 location_id);
-void release_start_screen();
-void reset_login();
-LLSD transform_cert_args(LLPointer<LLCertificate> cert);
-void general_cert_done(const LLSD& notification, const LLSD& response);
-void trust_cert_done(const LLSD& notification, const LLSD& response);
-void apply_udp_blacklist(const std::string& csv);
-bool process_login_success_response();
-void transition_back_to_login_panel(const std::string& emsg);
-
-void callback_cache_name(const LLUUID& id, const std::string& full_name, bool is_group)
-{
- LLNameBox::refreshAll(id, full_name, is_group);
- LLNameEditor::refreshAll(id, full_name, is_group);
-
- // TODO: Actually be intelligent about the refresh.
- // For now, just brute force refresh the dialogs.
- dialog_refresh_all();
-}
-
-//
-// exported functionality
-//
-
-//
-// local classes
-//
-
-namespace
-{
- class LLNullHTTPSender : public LLHTTPSender
- {
- virtual void send(const LLHost& host,
- const std::string& message, const LLSD& body,
- LLHTTPClient::ResponderPtr response) const
- {
- LL_WARNS("AppInit") << " attemped to send " << message << " to " << host
- << " with null sender" << LL_ENDL;
- }
- };
-}
-
-void update_texture_fetch()
-{
- LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread
- LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread
- LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread
- gTextureList.updateImages(0.10f);
-}
-
-// Returns false to skip other idle processing. Should only return
-// true when all initialization done.
-bool idle_startup()
-{
- LLMemType mt1(LLMemType::MTYPE_STARTUP);
-
- const F32 PRECACHING_DELAY = gSavedSettings.getF32("PrecachingDelay");
- static LLTimer timeout;
- static S32 timeout_count = 0;
-
- static LLTimer login_time;
-
- // until this is encapsulated, this little hack for the
- // auth/transform loop will do.
- static F32 progress = 0.10f;
-
- static std::string auth_desc;
- static std::string auth_message;
-
- static LLVector3 initial_sun_direction(1.f, 0.f, 0.f);
- static LLVector3 agent_start_position_region(10.f, 10.f, 10.f); // default for when no space server
-
- // last location by default
- static S32 agent_location_id = START_LOCATION_ID_LAST;
- static S32 location_which = START_LOCATION_ID_LAST;
-
- static bool show_connect_box = true;
-
- //static bool stipend_since_login = false;
-
- // HACK: These are things from the main loop that usually aren't done
- // until initialization is complete, but need to be done here for things
- // to work.
- gIdleCallbacks.callFunctions();
- gViewerWindow->updateUI();
- LLMortician::updateClass();
-
- const std::string delims (" ");
- std::string system;
- int begIdx, endIdx;
- std::string osString = LLAppViewer::instance()->getOSInfo().getOSStringSimple();
-
- begIdx = osString.find_first_not_of (delims);
- endIdx = osString.find_first_of (delims, begIdx);
- system = osString.substr (begIdx, endIdx - begIdx);
- system += "Locale";
-
- LLStringUtil::setLocale (LLTrans::getString(system));
-
- if (!gNoRender)
- {
- //note: Removing this line will cause incorrect button size in the login screen. -- bao.
- gTextureList.updateImages(0.01f) ;
- }
-
- if ( STATE_FIRST == LLStartUp::getStartupState() )
- {
- gViewerWindow->showCursor();
- gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT);
-
- /////////////////////////////////////////////////
- //
- // Initialize stuff that doesn't need data from simulators
- //
-
- if (LLFeatureManager::getInstance()->isSafe())
- {
- LLNotificationsUtil::add("DisplaySetToSafe");
- }
- else if ((gSavedSettings.getS32("LastFeatureVersion") < LLFeatureManager::getInstance()->getVersion()) &&
- (gSavedSettings.getS32("LastFeatureVersion") != 0))
- {
- LLNotificationsUtil::add("DisplaySetToRecommended");
- }
- else if ((gSavedSettings.getS32("LastGPUClass") != LLFeatureManager::getInstance()->getGPUClass()) &&
- (gSavedSettings.getS32("LastGPUClass") != -1))
- {
- LLNotificationsUtil::add("DisplaySetToRecommended");
- }
- else if (!gViewerWindow->getInitAlert().empty())
- {
- LLNotificationsUtil::add(gViewerWindow->getInitAlert());
- }
-
- gSavedSettings.setS32("LastFeatureVersion", LLFeatureManager::getInstance()->getVersion());
- gSavedSettings.setS32("LastGPUClass", LLFeatureManager::getInstance()->getGPUClass());
-
- // load dynamic GPU/feature tables from website (S3)
- LLFeatureManager::getInstance()->fetchHTTPTables();
-
- std::string xml_file = LLUI::locateSkin("xui_version.xml");
- LLXMLNodePtr root;
- bool xml_ok = false;
- if (LLXMLNode::parseFile(xml_file, root, NULL))
- {
- if( (root->hasName("xui_version") ) )
- {
- std::string value = root->getValue();
- F32 version = 0.0f;
- LLStringUtil::convertToF32(value, version);
- if (version >= 1.0f)
- {
- xml_ok = true;
- }
- }
- }
- if (!xml_ok)
- {
- // If XML is bad, there's a good possibility that notifications.xml is ALSO bad.
- // If that's so, then we'll get a fatal error on attempting to load it,
- // which will display a nontranslatable error message that says so.
- // Otherwise, we'll display a reasonable error message that IS translatable.
- LLAppViewer::instance()->earlyExit("BadInstallation");
- }
- //
- // Statistics stuff
- //
-
- // Load autopilot and stats stuff
- gAgentPilot.load(gSavedSettings.getString("StatsPilotFile"));
-
- //gErrorStream.setTime(gSavedSettings.getBOOL("LogTimestamps"));
-
- // Load the throttle settings
- gViewerThrottle.load();
-
- if (ll_init_ares() == NULL || !gAres->isInitialized())
- {
- std::string diagnostic = "Could not start address resolution system";
- LL_WARNS("AppInit") << diagnostic << LL_ENDL;
- LLAppViewer::instance()->earlyExit("LoginFailedNoNetwork", LLSD().with("DIAGNOSTIC", diagnostic));
- }
-
- //
- // Initialize messaging system
- //
- LL_DEBUGS("AppInit") << "Initializing messaging system..." << LL_ENDL;
-
- std::string message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message_template.msg");
-
- LLFILE* found_template = NULL;
- found_template = LLFile::fopen(message_template_path, "r"); /* Flawfinder: ignore */
-
- #if LL_WINDOWS
- // On the windows dev builds, unpackaged, the message_template.msg
- // file will be located in:
- // build-vc**/newview/<config>/app_settings
- if (!found_template)
- {
- message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "message_template.msg");
- found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */
- }
- #elif LL_DARWIN
- // On Mac dev builds, message_template.msg lives in:
- // indra/build-*/newview/<config>/Second Life/Contents/Resources/app_settings
- if (!found_template)
- {
- message_template_path =
- gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE,
- "../Resources/app_settings",
- "message_template.msg");
- found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */
- }
- #endif
-
- if (found_template)
- {
- fclose(found_template);
-
- U32 port = gSavedSettings.getU32("UserConnectionPort");
-
- if ((NET_USE_OS_ASSIGNED_PORT == port) && // if nothing specified on command line (-port)
- (gSavedSettings.getBOOL("ConnectionPortEnabled")))
- {
- port = gSavedSettings.getU32("ConnectionPort");
- }
-
- LLHTTPSender::setDefaultSender(new LLNullHTTPSender());
-
- // TODO parameterize
- const F32 circuit_heartbeat_interval = 5;
- const F32 circuit_timeout = 100;
-
- const LLUseCircuitCodeResponder* responder = NULL;
- bool failure_is_fatal = true;
-
- if(!start_messaging_system(
- message_template_path,
- port,
- LLVersionInfo::getMajor(),
- LLVersionInfo::getMinor(),
- LLVersionInfo::getPatch(),
- FALSE,
- std::string(),
- responder,
- failure_is_fatal,
- circuit_heartbeat_interval,
- circuit_timeout))
- {
- std::string diagnostic = llformat(" Error: %d", gMessageSystem->getErrorCode());
- LL_WARNS("AppInit") << diagnostic << LL_ENDL;
- LLAppViewer::instance()->earlyExit("LoginFailedNoNetwork", LLSD().with("DIAGNOSTIC", diagnostic));
- }
-
- #if LL_WINDOWS
- // On the windows dev builds, unpackaged, the message.xml file will
- // be located in indra/build-vc**/newview/<config>/app_settings.
- std::string message_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message.xml");
-
- if (!LLFile::isfile(message_path.c_str()))
- {
- LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", ""));
- }
- else
- {
- LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
- }
- #else
- LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
- #endif
-
- }
- else
- {
- LLAppViewer::instance()->earlyExit("MessageTemplateNotFound", LLSD().with("PATH", message_template_path));
- }
-
- if(gMessageSystem && gMessageSystem->isOK())
- {
- // Initialize all of the callbacks in case of bad message
- // system data
- LLMessageSystem* msg = gMessageSystem;
- msg->setExceptionFunc(MX_UNREGISTERED_MESSAGE,
- invalid_message_callback,
- NULL);
- msg->setExceptionFunc(MX_PACKET_TOO_SHORT,
- invalid_message_callback,
- NULL);
-
- // running off end of a packet is now valid in the case
- // when a reader has a newer message template than
- // the sender
- /*msg->setExceptionFunc(MX_RAN_OFF_END_OF_PACKET,
- invalid_message_callback,
- NULL);*/
- msg->setExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE,
- invalid_message_callback,
- NULL);
-
- if (gSavedSettings.getBOOL("LogMessages"))
- {
- LL_DEBUGS("AppInit") << "Message logging activated!" << LL_ENDL;
- msg->startLogging();
- }
-
- // start the xfer system. by default, choke the downloads
- // a lot...
- const S32 VIEWER_MAX_XFER = 3;
- start_xfer_manager(gVFS);
- gXferManager->setMaxIncomingXfers(VIEWER_MAX_XFER);
- F32 xfer_throttle_bps = gSavedSettings.getF32("XferThrottle");
- if (xfer_throttle_bps > 1.f)
- {
- gXferManager->setUseAckThrottling(TRUE);
- gXferManager->setAckThrottleBPS(xfer_throttle_bps);
- }
- gAssetStorage = new LLViewerAssetStorage(msg, gXferManager, gVFS, gStaticVFS);
-
-
- F32 dropPercent = gSavedSettings.getF32("PacketDropPercentage");
- msg->mPacketRing.setDropPercentage(dropPercent);
-
- F32 inBandwidth = gSavedSettings.getF32("InBandwidth");
- F32 outBandwidth = gSavedSettings.getF32("OutBandwidth");
- if (inBandwidth != 0.f)
- {
- LL_DEBUGS("AppInit") << "Setting packetring incoming bandwidth to " << inBandwidth << LL_ENDL;
- msg->mPacketRing.setUseInThrottle(TRUE);
- msg->mPacketRing.setInBandwidth(inBandwidth);
- }
- if (outBandwidth != 0.f)
- {
- LL_DEBUGS("AppInit") << "Setting packetring outgoing bandwidth to " << outBandwidth << LL_ENDL;
- msg->mPacketRing.setUseOutThrottle(TRUE);
- msg->mPacketRing.setOutBandwidth(outBandwidth);
- }
- }
-
- LL_INFOS("AppInit") << "Message System Initialized." << LL_ENDL;
-
- //-------------------------------------------------
- // Init audio, which may be needed for prefs dialog
- // or audio cues in connection UI.
- //-------------------------------------------------
-
- if (FALSE == gSavedSettings.getBOOL("NoAudio"))
- {
- gAudiop = NULL;
-
-#ifdef LL_OPENAL
- if (!gAudiop
-#if !LL_WINDOWS
- && NULL == getenv("LL_BAD_OPENAL_DRIVER")
-#endif // !LL_WINDOWS
- )
- {
- gAudiop = (LLAudioEngine *) new LLAudioEngine_OpenAL();
- }
-#endif
-
-#ifdef LL_FMOD
- if (!gAudiop
-#if !LL_WINDOWS
- && NULL == getenv("LL_BAD_FMOD_DRIVER")
-#endif // !LL_WINDOWS
- )
- {
- gAudiop = (LLAudioEngine *) new LLAudioEngine_FMOD();
- }
-#endif
-
- if (gAudiop)
- {
-#if LL_WINDOWS
- // FMOD on Windows needs the window handle to stop playing audio
- // when window is minimized. JC
- void* window_handle = (HWND)gViewerWindow->getPlatformWindow();
-#else
- void* window_handle = NULL;
-#endif
- bool init = gAudiop->init(kAUDIO_NUM_SOURCES, window_handle);
- if(init)
- {
- gAudiop->setMuted(TRUE);
- }
- else
- {
- LL_WARNS("AppInit") << "Unable to initialize audio engine" << LL_ENDL;
- delete gAudiop;
- gAudiop = NULL;
- }
-
- if (gAudiop)
- {
- // if the audio engine hasn't set up its own preferred handler for streaming audio then set up the generic streaming audio implementation which uses media plugins
- if (NULL == gAudiop->getStreamingAudioImpl())
- {
- LL_INFOS("AppInit") << "Using media plugins to render streaming audio" << LL_ENDL;
- gAudiop->setStreamingAudioImpl(new LLStreamingAudio_MediaPlugins());
- }
- }
- }
- }
-
- LL_INFOS("AppInit") << "Audio Engine Initialized." << LL_ENDL;
-
- if (LLTimer::knownBadTimer())
- {
- LL_WARNS("AppInit") << "Unreliable timers detected (may be bad PCI chipset)!!" << LL_ENDL;
- }
-
- //
- // Log on to system
- //
- if (gUserCredential.isNull())
- {
- gUserCredential = gLoginHandler.initializeLoginInfo();
- }
- if (gUserCredential.isNull())
- {
- show_connect_box = TRUE;
- }
- else if (gSavedSettings.getBOOL("AutoLogin"))
- {
- gRememberPassword = TRUE;
- gSavedSettings.setBOOL("RememberPassword", TRUE);
- show_connect_box = false;
- }
- else
- {
- gRememberPassword = gSavedSettings.getBOOL("RememberPassword");
- show_connect_box = TRUE;
- }
- // Go to the next startup state
- LLStartUp::setStartupState( STATE_BROWSER_INIT );
- return FALSE;
- }
-
-
- if (STATE_BROWSER_INIT == LLStartUp::getStartupState())
- {
- LL_DEBUGS("AppInit") << "STATE_BROWSER_INIT" << LL_ENDL;
- std::string msg = LLTrans::getString("LoginInitializingBrowser");
- set_startup_status(0.03f, msg.c_str(), gAgent.mMOTD.c_str());
- display_startup();
- // LLViewerMedia::initBrowser();
- LLStartUp::setStartupState( STATE_LOGIN_SHOW );
- return FALSE;
- }
-
-
- if (STATE_LOGIN_SHOW == LLStartUp::getStartupState())
- {
- LL_DEBUGS("AppInit") << "Initializing Window" << LL_ENDL;
-
- // if we've gone backwards in the login state machine, to this state where we show the UI
- // AND the debug setting to exit in this case is true, then go ahead and bail quickly
- if ( mLoginStatePastUI && gSavedSettings.getBOOL("QuitOnLoginActivated") )
- {
- // no requirement for notification here - just exit
- LLAppViewer::instance()->earlyExitNoNotify();
- }
-
- gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW);
-
- timeout_count = 0;
-
- if (show_connect_box)
- {
- // Load all the name information out of the login view
- // NOTE: Hits "Attempted getFields with no login view shown" warning, since we don't
- // show the login view until login_show() is called below.
- if (gUserCredential.isNull())
- {
- gUserCredential = gLoginHandler.initializeLoginInfo();
- }
- if (gNoRender)
- {
- LL_ERRS("AppInit") << "Need to autologin or use command line with norender!" << LL_ENDL;
- }
- // Make sure the process dialog doesn't hide things
- gViewerWindow->setShowProgress(FALSE);
-
- initialize_edit_menu();
-
- // Show the login dialog
- login_show();
- // connect dialog is already shown, so fill in the names
- if (gUserCredential.notNull())
- {
- LLPanelLogin::setFields( gUserCredential, gRememberPassword);
- }
- LLPanelLogin::giveFocus();
-
- gSavedSettings.setBOOL("FirstRunThisInstall", FALSE);
-
- LLStartUp::setStartupState( STATE_LOGIN_WAIT ); // Wait for user input
- }
- else
- {
- // skip directly to message template verification
- LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
- }
-
- // *NOTE: This is where LLViewerParcelMgr::getInstance() used to get allocated before becoming LLViewerParcelMgr::getInstance().
-
- // *NOTE: This is where gHUDManager used to bet allocated before becoming LLHUDManager::getInstance().
-
- // *NOTE: This is where gMuteList used to get allocated before becoming LLMuteList::getInstance().
-
- // Login screen needs menus for preferences, but we can enter
- // this startup phase more than once.
- if (gLoginMenuBarView == NULL)
- {
- init_menus();
- }
-
- gViewerWindow->setNormalControlsVisible( FALSE );
- gLoginMenuBarView->setVisible( TRUE );
- gLoginMenuBarView->setEnabled( TRUE );
- show_debug_menus();
-
- // Hide the splash screen
- LLSplashScreen::hide();
-
- // Push our window frontmost
- gViewerWindow->getWindow()->show();
- display_startup();
-
- // DEV-16927. The following code removes errant keystrokes that happen while the window is being
- // first made visible.
-#ifdef _WIN32
- MSG msg;
- while( PeekMessage( &msg, /*All hWnds owned by this thread */ NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) );
-#endif
- timeout.reset();
- return FALSE;
- }
-
- if (STATE_LOGIN_WAIT == LLStartUp::getStartupState())
- {
- // when we get to this state, we've already been past the login UI
- // (possiblely automatically) - flag this so we can test in the
- // STATE_LOGIN_SHOW state if we've gone backwards
- mLoginStatePastUI = true;
-
- // Don't do anything. Wait for the login view to call the login_callback,
- // which will push us to the next state.
-
- // Sleep so we don't spin the CPU
- ms_sleep(1);
- return FALSE;
- }
-
- if (STATE_LOGIN_CLEANUP == LLStartUp::getStartupState())
- {
- //reset the values that could have come in from a slurl
- // DEV-42215: Make sure they're not empty -- gUserCredential
- // might already have been set from gSavedSettings, and it's too bad
- // to overwrite valid values with empty strings.
-
- if (show_connect_box)
- {
- // TODO if not use viewer auth
- // Load all the name information out of the login view
- LLPanelLogin::getFields(gUserCredential, gRememberPassword);
- // end TODO
-
- // HACK: Try to make not jump on login
- gKeyboard->resetKeys();
- }
-
- // when we get to this state, we've already been past the login UI
- // (possiblely automatically) - flag this so we can test in the
- // STATE_LOGIN_SHOW state if we've gone backwards
- mLoginStatePastUI = true;
-
- // save the credentials
- std::string userid = "unknown";
- if(gUserCredential.notNull())
- {
- userid = gUserCredential->userID();
- gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword);
- }
- gSavedSettings.setBOOL("RememberPassword", gRememberPassword);
- LL_INFOS("AppInit") << "Attempting login as: " << userid << LL_ENDL;
- gDebugInfo["LoginName"] = userid;
-
- // create necessary directories
- // *FIX: these mkdir's should error check
- gDirUtilp->setLindenUserDir(userid);
- LLFile::mkdir(gDirUtilp->getLindenUserDir());
-
- // Set PerAccountSettingsFile to the default value.
- std::string per_account_settings_file = LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount");
- gSavedSettings.setString("PerAccountSettingsFile",
- gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT,
- LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount")));
-
- // Note: can't store warnings files per account because some come up before login
-
- // Overwrite default user settings with user settings
- LLAppViewer::instance()->loadSettingsFromDirectory("Account");
-
- // Need to set the LastLogoff time here if we don't have one. LastLogoff is used for "Recent Items" calculation
- // and startup time is close enough if we don't have a real value.
- if (gSavedPerAccountSettings.getU32("LastLogoff") == 0)
- {
- gSavedPerAccountSettings.setU32("LastLogoff", time_corrected());
- }
-
- //Default the path if one isn't set.
- // *NOTE: unable to check variable differ from "InstantMessageLogPath" because it was
- // provided in pre 2.0 viewer. See EXT-6661
- if (gSavedPerAccountSettings.getString("InstantMessageLogPath").empty())
- {
- gDirUtilp->setChatLogsDir(gDirUtilp->getOSUserAppDir());
- gSavedPerAccountSettings.setString("InstantMessageLogPath", gDirUtilp->getChatLogsDir());
- }
- else
- {
- gDirUtilp->setChatLogsDir(gSavedPerAccountSettings.getString("InstantMessageLogPath"));
- }
- gDirUtilp->setPerAccountChatLogsDir(userid);
-
- LLFile::mkdir(gDirUtilp->getChatLogsDir());
- LLFile::mkdir(gDirUtilp->getPerAccountChatLogsDir());
-
-
- //good a place as any to create user windlight directories
- std::string user_windlight_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight", ""));
- LLFile::mkdir(user_windlight_path_name.c_str());
-
- std::string user_windlight_skies_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", ""));
- LLFile::mkdir(user_windlight_skies_path_name.c_str());
-
- std::string user_windlight_water_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/water", ""));
- LLFile::mkdir(user_windlight_water_path_name.c_str());
-
- std::string user_windlight_days_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/days", ""));
- LLFile::mkdir(user_windlight_days_path_name.c_str());
-
-
- if (show_connect_box)
- {
- LLSLURL slurl;
- LLPanelLogin::closePanel();
- }
-
-
- // Load URL History File
- LLURLHistory::loadFile("url_history.xml");
- // Load location history
- LLLocationHistory::getInstance()->load();
-
- // Load Avatars icons cache
- LLAvatarIconIDCache::getInstance()->load();
-
- // Load media plugin cookies
- LLViewerMedia::loadCookieFile();
-
- //-------------------------------------------------
- // Handle startup progress screen
- //-------------------------------------------------
-
- // on startup the user can request to go to their home,
- // their last location, or some URL "-url //sim/x/y[/z]"
- // All accounts have both a home and a last location, and we don't support
- // more locations than that. Choose the appropriate one. JC
- switch (LLStartUp::getStartSLURL().getType())
- {
- case LLSLURL::LOCATION:
- agent_location_id = START_LOCATION_ID_URL;
- location_which = START_LOCATION_ID_LAST;
- break;
- case LLSLURL::LAST_LOCATION:
- agent_location_id = START_LOCATION_ID_LAST;
- location_which = START_LOCATION_ID_LAST;
- break;
- default:
- agent_location_id = START_LOCATION_ID_HOME;
- location_which = START_LOCATION_ID_HOME;
- break;
- }
-
- gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT);
-
- if (!gNoRender)
- {
- init_start_screen(agent_location_id);
- }
-
- // Display the startup progress bar.
- gViewerWindow->setShowProgress(TRUE);
- gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Quit"));
-
- // Poke the VFS, which could potentially block for a while if
- // Windows XP is acting up
- set_startup_status(0.07f, LLTrans::getString("LoginVerifyingCache"), LLStringUtil::null);
- display_startup();
-
- gVFS->pokeFiles();
-
- LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT );
-
- return FALSE;
- }
-
- if(STATE_LOGIN_AUTH_INIT == LLStartUp::getStartupState())
- {
- gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridLabel();
-
- // Update progress status and the display loop.
- auth_desc = LLTrans::getString("LoginInProgress");
- set_startup_status(progress, auth_desc, auth_message);
- progress += 0.02f;
- display_startup();
-
- // Setting initial values...
- LLLoginInstance* login = LLLoginInstance::getInstance();
- login->setNotificationsInterface(LLNotifications::getInstance());
- if(gNoRender)
- {
- // HACK, skip optional updates if you're running drones
- login->setSkipOptionalUpdate(true);
- }
-
- login->setSerialNumber(LLAppViewer::instance()->getSerialNumber());
- login->setLastExecEvent(gLastExecEvent);
- login->setUpdaterLauncher(boost::bind(&LLAppViewer::launchUpdater, LLAppViewer::instance()));
-
- // This call to LLLoginInstance::connect() starts the
- // authentication process.
- login->connect(gUserCredential);
-
- LLStartUp::setStartupState( STATE_LOGIN_CURL_UNSTUCK );
- return FALSE;
- }
-
- if(STATE_LOGIN_CURL_UNSTUCK == LLStartUp::getStartupState())
- {
- // If we get here we have gotten past the potential stall
- // in curl, so take "may appear frozen" out of progress bar. JC
- auth_desc = LLTrans::getString("LoginInProgressNoFrozen");
- set_startup_status(progress, auth_desc, auth_message);
-
- LLStartUp::setStartupState( STATE_LOGIN_PROCESS_RESPONSE );
- return FALSE;
- }
-
- if(STATE_LOGIN_PROCESS_RESPONSE == LLStartUp::getStartupState())
- {
- std::ostringstream emsg;
- emsg << LLTrans::getString("LoginFailed") << "\n";
- if(LLLoginInstance::getInstance()->authFailure())
- {
- LL_INFOS("LLStartup") << "Login failed, LLLoginInstance::getResponse(): "
- << LLLoginInstance::getInstance()->getResponse() << LL_ENDL;
- LLSD response = LLLoginInstance::getInstance()->getResponse();
- // Still have error conditions that may need some
- // sort of handling.
- std::string reason_response = response["reason"];
- std::string message_response = response["message"];
-
- if(!message_response.empty())
- {
- // XUI: fix translation for strings returned during login
- // We need a generic table for translations
- std::string big_reason = LLAgent::sTeleportErrorMessages[ message_response ];
- if ( big_reason.size() == 0 )
- {
- emsg << message_response;
- }
- else
- {
- emsg << big_reason;
- }
- }
-
- if(reason_response == "key")
- {
- // Couldn't login because user/password is wrong
- // Clear the credential
- gUserCredential->clearAuthenticator();
- }
-
- if(reason_response == "update"
- || reason_response == "optional")
- {
- // In the case of a needed update, quit.
- // Its either downloading or declined.
- // If optional was skipped this case shouldn't
- // be reached.
- LLLoginInstance::getInstance()->disconnect();
- LLAppViewer::instance()->forceQuit();
- }
- else
- {
- if (reason_response != "tos")
- {
- // Don't pop up a notification in the TOS case because
- // LLFloaterTOS::onCancel() already scolded the user.
- std::string error_code;
- if(response.has("errorcode"))
- {
- error_code = response["errorcode"].asString();
- }
- if ((reason_response == "CURLError") &&
- (error_code == "SSL_CACERT" || error_code == "SSL_PEER_CERTIFICATE") &&
- response.has("certificate"))
- {
- // This was a certificate error, so grab the certificate
- // and throw up the appropriate dialog.
- LLPointer<LLCertificate> certificate = gSecAPIHandler->getCertificate(response["certificate"]);
- if(certificate)
- {
- LLSD args = transform_cert_args(certificate);
-
- if(error_code == "SSL_CACERT")
- {
- // if we are handling an untrusted CA, throw up the dialog
- // with the 'trust this CA' button.
- LLNotificationsUtil::add("TrustCertificateError", args, response,
- trust_cert_done);
-
- show_connect_box = true;
- }
- else
- {
- // the certificate exception returns a unique string for each type of exception.
- // we grab this string via the LLUserAuth object, and use that to grab the localized
- // string.
- args["REASON"] = LLTrans::getString(message_response);
-
- LLNotificationsUtil::add("GeneralCertificateError", args, response,
- general_cert_done);
-
- reset_login();
- gSavedSettings.setBOOL("AutoLogin", FALSE);
- show_connect_box = true;
-
- }
-
- }
- }
- else
- {
- // This wasn't a certificate error, so throw up the normal
- // notificatioin message.
- LLSD args;
- args["ERROR_MESSAGE"] = emsg.str();
- LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL;
- LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done);
- }
- }
- //setup map of datetime strings to codes and slt & local time offset from utc
- // *TODO: Does this need to be here?
- LLStringOps::setupDatetimeInfo (false);
- transition_back_to_login_panel(emsg.str());
- show_connect_box = true;
- }
- }
- else if(LLLoginInstance::getInstance()->authSuccess())
- {
- if(process_login_success_response())
- {
- // Pass the user information to the voice chat server interface.
- LLVoiceClient::getInstance()->userAuthorized(gUserCredential->userID(), gAgentID);
- // create the default proximal channel
- LLVoiceChannel::initClass();
- LLGridManager::getInstance()->setFavorite();
- LLStartUp::setStartupState( STATE_WORLD_INIT);
- }
- else
- {
- LLSD args;
- args["ERROR_MESSAGE"] = emsg.str();
- LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL;
- LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done);
- transition_back_to_login_panel(emsg.str());
- show_connect_box = true;
- return FALSE;
- }
- }
- return FALSE;
- }
-
- //---------------------------------------------------------------------
- // World Init
- //---------------------------------------------------------------------
- if (STATE_WORLD_INIT == LLStartUp::getStartupState())
- {
- set_startup_status(0.30f, LLTrans::getString("LoginInitializingWorld"), gAgent.mMOTD);
- display_startup();
- // We should have an agent id by this point.
- llassert(!(gAgentID == LLUUID::null));
-
- // Finish agent initialization. (Requires gSavedSettings, builds camera)
- gAgent.init();
- gAgentCamera.init();
- set_underclothes_menu_options();
-
- // Since we connected, save off the settings so the user doesn't have to
- // type the name/password again if we crash.
- gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE);
- LLUIColorTable::instance().saveUserSettings();
-
- //
- // Initialize classes w/graphics stuff.
- //
- gTextureList.doPrefetchImages();
- LLSurface::initClasses();
-
- LLFace::initClass();
-
- LLDrawable::initClass();
-
- // init the shader managers
- LLPostProcess::initClass();
- LLWLParamManager::initClass();
- LLWaterParamManager::initClass();
-
- LLViewerObject::initVOClasses();
-
- // Initialize all our tools. Must be done after saved settings loaded.
- // NOTE: This also is where gToolMgr used to be instantiated before being turned into a singleton.
- LLToolMgr::getInstance()->initTools();
-
- // Pre-load floaters, like the world map, that are slow to spawn
- // due to XML complexity.
- gViewerWindow->initWorldUI();
-
- display_startup();
-
- // This is where we used to initialize gWorldp. Original comment said:
- // World initialization must be done after above window init
-
- // User might have overridden far clip
- LLWorld::getInstance()->setLandFarClip(gAgentCamera.mDrawDistance);
-
- // Before we create the first region, we need to set the agent's mOriginGlobal
- // This is necessary because creating objects before this is set will result in a
- // bad mPositionAgent cache.
-
- gAgent.initOriginGlobal(from_region_handle(gFirstSimHandle));
-
- LLWorld::getInstance()->addRegion(gFirstSimHandle, gFirstSim);
-
- LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle);
- LL_INFOS("AppInit") << "Adding initial simulator " << regionp->getOriginGlobal() << LL_ENDL;
-
- regionp->setSeedCapability(gFirstSimSeedCap);
- LL_DEBUGS("AppInit") << "Waiting for seed grant ...." << LL_ENDL;
-
- // Set agent's initial region to be the one we just created.
- gAgent.setRegion(regionp);
-
- // Set agent's initial position, which will be read by LLVOAvatar when the avatar
- // object is created. I think this must be done after setting the region. JC
- gAgent.setPositionAgent(agent_start_position_region);
-
- display_startup();
- LLStartUp::setStartupState( STATE_MULTIMEDIA_INIT );
-
- return FALSE;
- }
-
-
- //---------------------------------------------------------------------
- // Load QuickTime/GStreamer and other multimedia engines, can be slow.
- // Do it while we're waiting on the network for our seed capability. JC
- //---------------------------------------------------------------------
- if (STATE_MULTIMEDIA_INIT == LLStartUp::getStartupState())
- {
- LLStartUp::multimediaInit();
- LLStartUp::setStartupState( STATE_FONT_INIT );
- return FALSE;
- }
-
- // Loading fonts takes several seconds
- if (STATE_FONT_INIT == LLStartUp::getStartupState())
- {
- LLStartUp::fontInit();
- LLStartUp::setStartupState( STATE_SEED_GRANTED_WAIT );
- return FALSE;
- }
-
- //---------------------------------------------------------------------
- // Wait for Seed Cap Grant
- //---------------------------------------------------------------------
- if(STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState())
- {
- return FALSE;
- }
-
-
- //---------------------------------------------------------------------
- // Seed Capability Granted
- // no newMessage calls should happen before this point
- //---------------------------------------------------------------------
- if (STATE_SEED_CAP_GRANTED == LLStartUp::getStartupState())
- {
- update_texture_fetch();
-
- if ( gViewerWindow != NULL)
- { // This isn't the first logon attempt, so show the UI
- gViewerWindow->setNormalControlsVisible( TRUE );
- }
- gLoginMenuBarView->setVisible( FALSE );
- gLoginMenuBarView->setEnabled( FALSE );
-
- if (!gNoRender)
- {
- // direct logging to the debug console's line buffer
- LLError::logToFixedBuffer(gDebugView->mDebugConsolep);
-
- // set initial visibility of debug console
- gDebugView->mDebugConsolep->setVisible(gSavedSettings.getBOOL("ShowDebugConsole"));
- }
-
- //
- // Set message handlers
- //
- LL_INFOS("AppInit") << "Initializing communications..." << LL_ENDL;
-
- // register callbacks for messages. . . do this after initial handshake to make sure that we don't catch any unwanted
- register_viewer_callbacks(gMessageSystem);
-
- // Debugging info parameters
- gMessageSystem->setMaxMessageTime( 0.5f ); // Spam if decoding all msgs takes more than 500 ms
-
- #ifndef LL_RELEASE_FOR_DOWNLOAD
- gMessageSystem->setTimeDecodes( TRUE ); // Time the decode of each msg
- gMessageSystem->setTimeDecodesSpamThreshold( 0.05f ); // Spam if a single msg takes over 50ms to decode
- #endif
-
- gXferManager->registerCallbacks(gMessageSystem);
-
- LLStartUp::initNameCache();
-
- // update the voice settings *after* gCacheName initialization
- // so that we can construct voice UI that relies on the name cache
- LLVoiceClient::getInstance()->updateSettings();
-
- //gCacheName is required for nearby chat history loading
- //so I just moved nearby history loading a few states further
- if (!gNoRender && gSavedPerAccountSettings.getBOOL("LogShowHistory"))
- {
- LLNearbyChat* nearby_chat = LLNearbyChat::getInstance();
- if (nearby_chat) nearby_chat->loadHistory();
- }
-
- // *Note: this is where gWorldMap used to be initialized.
-
- // register null callbacks for audio until the audio system is initialized
- gMessageSystem->setHandlerFuncFast(_PREHASH_SoundTrigger, null_message_callback, NULL);
- gMessageSystem->setHandlerFuncFast(_PREHASH_AttachedSound, null_message_callback, NULL);
-
- //reset statistics
- LLViewerStats::getInstance()->resetStats();
-
- display_startup();
- //
- // Set up region and surface defaults
- //
-
-
- // Sets up the parameters for the first simulator
-
- LL_DEBUGS("AppInit") << "Initializing camera..." << LL_ENDL;
- gFrameTime = totalTime();
- F32 last_time = gFrameTimeSeconds;
- gFrameTimeSeconds = (S64)(gFrameTime - gStartTime)/SEC_TO_MICROSEC;
-
- gFrameIntervalSeconds = gFrameTimeSeconds - last_time;
- if (gFrameIntervalSeconds < 0.f)
- {
- gFrameIntervalSeconds = 0.f;
- }
-
- // Make sure agent knows correct aspect ratio
- // FOV limits depend upon aspect ratio so this needs to happen before initializing the FOV below
- LLViewerCamera::getInstance()->setViewHeightInPixels(gViewerWindow->getWorldViewHeightRaw());
- LLViewerCamera::getInstance()->setAspect(gViewerWindow->getWorldViewAspectRatio());
- // Initialize FOV
- LLViewerCamera::getInstance()->setDefaultFOV(gSavedSettings.getF32("CameraAngle"));
-
- // Move agent to starting location. The position handed to us by
- // the space server is in global coordinates, but the agent frame
- // is in region local coordinates. Therefore, we need to adjust
- // the coordinates handed to us to fit in the local region.
-
- gAgent.setPositionAgent(agent_start_position_region);
- gAgent.resetAxes(gAgentStartLookAt);
- gAgentCamera.stopCameraAnimation();
- gAgentCamera.resetCamera();
-
- // Initialize global class data needed for surfaces (i.e. textures)
- if (!gNoRender)
- {
- LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL;
- // Initialize all of the viewer object classes for the first time (doing things like texture fetches.
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
-
- gSky.init(initial_sun_direction);
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- }
-
- LL_DEBUGS("AppInit") << "Decoding images..." << LL_ENDL;
- // For all images pre-loaded into viewer cache, decode them.
- // Need to do this AFTER we init the sky
- const S32 DECODE_TIME_SEC = 2;
- for (int i = 0; i < DECODE_TIME_SEC; i++)
- {
- F32 frac = (F32)i / (F32)DECODE_TIME_SEC;
- set_startup_status(0.45f + frac*0.1f, LLTrans::getString("LoginDecodingImages"), gAgent.mMOTD);
- display_startup();
- gTextureList.decodeAllImages(1.f);
- }
- LLStartUp::setStartupState( STATE_WORLD_WAIT );
-
- // JC - Do this as late as possible to increase likelihood Purify
- // will run.
- LLMessageSystem* msg = gMessageSystem;
- if (!msg->mOurCircuitCode)
- {
- LL_WARNS("AppInit") << "Attempting to connect to simulator with a zero circuit code!" << LL_ENDL;
- }
-
- gUseCircuitCallbackCalled = false;
-
- msg->enableCircuit(gFirstSim, TRUE);
- // now, use the circuit info to tell simulator about us!
- LL_INFOS("AppInit") << "viewer: UserLoginLocationReply() Enabling " << gFirstSim << " with code " << msg->mOurCircuitCode << LL_ENDL;
- msg->newMessageFast(_PREHASH_UseCircuitCode);
- msg->nextBlockFast(_PREHASH_CircuitCode);
- msg->addU32Fast(_PREHASH_Code, msg->mOurCircuitCode);
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->addUUIDFast(_PREHASH_ID, gAgent.getID());
- msg->sendReliable(
- gFirstSim,
- gSavedSettings.getS32("UseCircuitCodeMaxRetries"),
- FALSE,
- gSavedSettings.getF32("UseCircuitCodeTimeout"),
- use_circuit_callback,
- NULL);
-
- timeout.reset();
-
- return FALSE;
- }
-
- //---------------------------------------------------------------------
- // Agent Send
- //---------------------------------------------------------------------
- if(STATE_WORLD_WAIT == LLStartUp::getStartupState())
- {
- LL_DEBUGS("AppInit") << "Waiting for simulator ack...." << LL_ENDL;
- set_startup_status(0.59f, LLTrans::getString("LoginWaitingForRegionHandshake"), gAgent.mMOTD);
- if(gGotUseCircuitCodeAck)
- {
- LLStartUp::setStartupState( STATE_AGENT_SEND );
- }
- LLMessageSystem* msg = gMessageSystem;
- while (msg->checkAllMessages(gFrameCount, gServicePump))
- {
- }
- msg->processAcks();
- return FALSE;
- }
-
- //---------------------------------------------------------------------
- // Agent Send
- //---------------------------------------------------------------------
- if (STATE_AGENT_SEND == LLStartUp::getStartupState())
- {
- LL_DEBUGS("AppInit") << "Connecting to region..." << LL_ENDL;
- set_startup_status(0.60f, LLTrans::getString("LoginConnectingToRegion"), gAgent.mMOTD);
- // register with the message system so it knows we're
- // expecting this message
- LLMessageSystem* msg = gMessageSystem;
- msg->setHandlerFuncFast(
- _PREHASH_AgentMovementComplete,
- process_agent_movement_complete);
- LLViewerRegion* regionp = gAgent.getRegion();
- if(regionp)
- {
- send_complete_agent_movement(regionp->getHost());
- gAssetStorage->setUpstream(regionp->getHost());
- gCacheName->setUpstream(regionp->getHost());
- msg->newMessageFast(_PREHASH_EconomyDataRequest);
- gAgent.sendReliableMessage();
- }
-
- // Create login effect
- // But not on first login, because you can't see your avatar then
- if (!gAgent.isFirstLogin())
- {
- LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
- effectp->setPositionGlobal(gAgent.getPositionGlobal());
- effectp->setColor(LLColor4U(gAgent.getEffectColor()));
- LLHUDManager::getInstance()->sendEffects();
- }
-
- LLStartUp::setStartupState( STATE_AGENT_WAIT ); // Go to STATE_AGENT_WAIT
-
- timeout.reset();
- return FALSE;
- }
-
- //---------------------------------------------------------------------
- // Agent Wait
- //---------------------------------------------------------------------
- if (STATE_AGENT_WAIT == LLStartUp::getStartupState())
- {
- LLMessageSystem* msg = gMessageSystem;
- while (msg->checkAllMessages(gFrameCount, gServicePump))
- {
- if (gAgentMovementCompleted)
- {
- // Sometimes we have more than one message in the
- // queue. break out of this loop and continue
- // processing. If we don't, then this could skip one
- // or more login steps.
- break;
- }
- else
- {
- LL_DEBUGS("AppInit") << "Awaiting AvatarInitComplete, got "
- << msg->getMessageName() << LL_ENDL;
- }
- }
- msg->processAcks();
-
- if (gAgentMovementCompleted)
- {
- LLStartUp::setStartupState( STATE_INVENTORY_SEND );
- }
-
- return FALSE;
- }
-
- //---------------------------------------------------------------------
- // Inventory Send
- //---------------------------------------------------------------------
- if (STATE_INVENTORY_SEND == LLStartUp::getStartupState())
- {
- // Inform simulator of our language preference
- LLAgentLanguage::update();
-
- // unpack thin inventory
- LLSD response = LLLoginInstance::getInstance()->getResponse();
- //bool dump_buffer = false;
-
- LLSD inv_lib_root = response["inventory-lib-root"];
- if(inv_lib_root.isDefined())
- {
- // should only be one
- LLSD id = inv_lib_root[0]["folder_id"];
- if(id.isDefined())
- {
- gInventory.setLibraryRootFolderID(id.asUUID());
- }
- }
-
- LLSD inv_lib_owner = response["inventory-lib-owner"];
- if(inv_lib_owner.isDefined())
- {
- // should only be one
- LLSD id = inv_lib_owner[0]["agent_id"];
- if(id.isDefined())
- {
- gInventory.setLibraryOwnerID( LLUUID(id.asUUID()));
- }
- }
-
- LLSD inv_skel_lib = response["inventory-skel-lib"];
- if(inv_skel_lib.isDefined() && gInventory.getLibraryOwnerID().notNull())
- {
- if(!gInventory.loadSkeleton(inv_skel_lib, gInventory.getLibraryOwnerID()))
- {
- LL_WARNS("AppInit") << "Problem loading inventory-skel-lib" << LL_ENDL;
- }
- }
-
- LLSD inv_skeleton = response["inventory-skeleton"];
- if(inv_skeleton.isDefined())
- {
- if(!gInventory.loadSkeleton(inv_skeleton, gAgent.getID()))
- {
- LL_WARNS("AppInit") << "Problem loading inventory-skel-targets" << LL_ENDL;
- }
- }
-
- LLSD buddy_list = response["buddy-list"];
- if(buddy_list.isDefined())
- {
- LLAvatarTracker::buddy_map_t list;
- LLUUID agent_id;
- S32 has_rights = 0, given_rights = 0;
- for(LLSD::array_const_iterator it = buddy_list.beginArray(),
- end = buddy_list.endArray(); it != end; ++it)
- {
- LLSD buddy_id = (*it)["buddy_id"];
- if(buddy_id.isDefined())
- {
- agent_id = buddy_id.asUUID();
- }
-
- LLSD buddy_rights_has = (*it)["buddy_rights_has"];
- if(buddy_rights_has.isDefined())
- {
- has_rights = buddy_rights_has.asInteger();
- }
-
- LLSD buddy_rights_given = (*it)["buddy_rights_given"];
- if(buddy_rights_given.isDefined())
- {
- given_rights = buddy_rights_given.asInteger();
- }
-
- list[agent_id] = new LLRelationship(given_rights, has_rights, false);
- }
- LLAvatarTracker::instance().addBuddyList(list);
- }
-
- bool show_hud = false;
- LLSD tutorial_setting = response["tutorial_setting"];
- if(tutorial_setting.isDefined())
- {
- for(LLSD::array_const_iterator it = tutorial_setting.beginArray(),
- end = tutorial_setting.endArray(); it != end; ++it)
- {
- LLSD tutorial_url = (*it)["tutorial_url"];
- if(tutorial_url.isDefined())
- {
- // Tutorial floater will append language code
- gSavedSettings.setString("TutorialURL", tutorial_url.asString());
- }
-
- // For Viewer 2.0 we are not using the web-based tutorial
- // If we reverse that decision, put this code back and use
- // login.cgi to send a different URL with content that matches
- // the Viewer 2.0 UI.
- //LLSD use_tutorial = (*it)["use_tutorial"];
- //if(use_tutorial.asString() == "true")
- //{
- // show_hud = true;
- //}
- }
- }
- // Either we want to show tutorial because this is the first login
- // to a Linden Help Island or the user quit with the tutorial
- // visible. JC
- if (show_hud || gSavedSettings.getBOOL("ShowTutorial"))
- {
- LLFloaterReg::showInstance("hud", LLSD(), FALSE);
- }
-
- LLSD event_notifications = response["event_notifications"];
- if(event_notifications.isDefined())
- {
- gEventNotifier.load(event_notifications);
- }
-
- LLSD classified_categories = response["classified_categories"];
- if(classified_categories.isDefined())
- {
- LLClassifiedInfo::loadCategories(classified_categories);
- }
-
- // This method MUST be called before gInventory.findCategoryUUIDForType because of
- // gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap.
- gInventory.buildParentChildMap();
-
- //all categories loaded. lets create "My Favorites" category
- gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE,true);
-
- // set up callbacks
- llinfos << "Registering Callbacks" << llendl;
- LLMessageSystem* msg = gMessageSystem;
- llinfos << " Inventory" << llendl;
- LLInventoryModel::registerCallbacks(msg);
- llinfos << " AvatarTracker" << llendl;
- LLAvatarTracker::instance().registerCallbacks(msg);
- llinfos << " Landmark" << llendl;
- LLLandmark::registerCallbacks(msg);
-
- // request mute list
- llinfos << "Requesting Mute List" << llendl;
- LLMuteList::getInstance()->requestFromServer(gAgent.getID());
-
- // Get L$ and ownership credit information
- llinfos << "Requesting Money Balance" << llendl;
- LLStatusBar::sendMoneyBalanceRequest();
-
- // request all group information
- llinfos << "Requesting Agent Data" << llendl;
- gAgent.sendAgentDataUpdateRequest();
-
- // Create the inventory views
- llinfos << "Creating Inventory Views" << llendl;
- LLFloaterReg::getInstance("inventory");
-
- LLStartUp::setStartupState( STATE_MISC );
- return FALSE;
- }
-
-
- //---------------------------------------------------------------------
- // Misc
- //---------------------------------------------------------------------
- if (STATE_MISC == LLStartUp::getStartupState())
- {
- // We have a region, and just did a big inventory download.
- // We can estimate the user's connection speed, and set their
- // max bandwidth accordingly. JC
- if (gSavedSettings.getBOOL("FirstLoginThisInstall"))
- {
- // This is actually a pessimistic computation, because TCP may not have enough
- // time to ramp up on the (small) default inventory file to truly measure max
- // bandwidth. JC
- F64 rate_bps = LLLoginInstance::getInstance()->getLastTransferRateBPS();
- const F32 FAST_RATE_BPS = 600.f * 1024.f;
- const F32 FASTER_RATE_BPS = 750.f * 1024.f;
- F32 max_bandwidth = gViewerThrottle.getMaxBandwidth();
- if (rate_bps > FASTER_RATE_BPS
- && rate_bps > max_bandwidth)
- {
- LL_DEBUGS("AppInit") << "Fast network connection, increasing max bandwidth to "
- << FASTER_RATE_BPS/1024.f
- << " kbps" << LL_ENDL;
- gViewerThrottle.setMaxBandwidth(FASTER_RATE_BPS / 1024.f);
- }
- else if (rate_bps > FAST_RATE_BPS
- && rate_bps > max_bandwidth)
- {
- LL_DEBUGS("AppInit") << "Fast network connection, increasing max bandwidth to "
- << FAST_RATE_BPS/1024.f
- << " kbps" << LL_ENDL;
- gViewerThrottle.setMaxBandwidth(FAST_RATE_BPS / 1024.f);
- }
-
- // Set the show start location to true, now that the user has logged
- // on with this install.
- gSavedSettings.setBOOL("ShowStartLocation", TRUE);
- }
-
- // We're successfully logged in.
- gSavedSettings.setBOOL("FirstLoginThisInstall", FALSE);
-
- LLFloaterReg::showInitialVisibleInstances();
-
- // based on the comments, we've successfully logged in so we can delete the 'forced'
- // URL that the updater set in settings.ini (in a mostly paranoid fashion)
- std::string nextLoginLocation = gSavedSettings.getString( "NextLoginLocation" );
- if ( nextLoginLocation.length() )
- {
- // clear it
- gSavedSettings.setString( "NextLoginLocation", "" );
-
- // and make sure it's saved
- gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile") , TRUE );
- LLUIColorTable::instance().saveUserSettings();
- };
-
- if (!gNoRender)
- {
- // JC: Initializing audio requests many sounds for download.
- init_audio();
-
- // JC: Initialize "active" gestures. This may also trigger
- // many gesture downloads, if this is the user's first
- // time on this machine or -purge has been run.
- LLSD gesture_options
- = LLLoginInstance::getInstance()->getResponse("gestures");
- if (gesture_options.isDefined())
- {
- LL_DEBUGS("AppInit") << "Gesture Manager loading " << gesture_options.size()
- << LL_ENDL;
- uuid_vec_t item_ids;
- for(LLSD::array_const_iterator resp_it = gesture_options.beginArray(),
- end = gesture_options.endArray(); resp_it != end; ++resp_it)
- {
- // If the id is not specifed in the LLSD,
- // the LLSD operator[]() will return a null LLUUID.
- LLUUID item_id = (*resp_it)["item_id"];
- LLUUID asset_id = (*resp_it)["asset_id"];
-
- if (item_id.notNull() && asset_id.notNull())
- {
- // Could schedule and delay these for later.
- const BOOL no_inform_server = FALSE;
- const BOOL no_deactivate_similar = FALSE;
- LLGestureMgr::instance().activateGestureWithAsset(item_id, asset_id,
- no_inform_server,
- no_deactivate_similar);
- // We need to fetch the inventory items for these gestures
- // so we have the names to populate the UI.
- item_ids.push_back(item_id);
- }
- }
- // no need to add gesture to inventory observer, it's already made in constructor
- LLGestureMgr::instance().setFetchIDs(item_ids);
- LLGestureMgr::instance().startFetch();
- }
- }
- gDisplaySwapBuffers = TRUE;
-
- LLMessageSystem* msg = gMessageSystem;
- msg->setHandlerFuncFast(_PREHASH_SoundTrigger, process_sound_trigger);
- msg->setHandlerFuncFast(_PREHASH_PreloadSound, process_preload_sound);
- msg->setHandlerFuncFast(_PREHASH_AttachedSound, process_attached_sound);
- msg->setHandlerFuncFast(_PREHASH_AttachedSoundGainChange, process_attached_sound_gain_change);
-
- LL_DEBUGS("AppInit") << "Initialization complete" << LL_ENDL;
-
- gRenderStartTime.reset();
- gForegroundTime.reset();
-
- // HACK: Inform simulator of window size.
- // Do this here so it's less likely to race with RegisterNewAgent.
- // TODO: Put this into RegisterNewAgent
- // JC - 7/20/2002
- gViewerWindow->sendShapeToSim();
-
-
- // Ignore stipend information for now. Money history is on the web site.
- // if needed, show the L$ history window
- //if (stipend_since_login && !gNoRender)
- //{
- //}
-
- // The reason we show the alert is because we want to
- // reduce confusion for when you log in and your provided
- // location is not your expected location. So, if this is
- // your first login, then you do not have an expectation,
- // thus, do not show this alert.
- if (!gAgent.isFirstLogin())
- {
- llinfos << "gAgentStartLocation : " << gAgentStartLocation << llendl;
- LLSLURL start_slurl = LLStartUp::getStartSLURL();
-
- if (((start_slurl.getType() == LLSLURL::LOCATION) && (gAgentStartLocation == "url")) ||
- ((start_slurl.getType() == LLSLURL::LAST_LOCATION) && (gAgentStartLocation == "last")) ||
- ((start_slurl.getType() == LLSLURL::HOME_LOCATION) && (gAgentStartLocation == "home")))
- {
- // Start location is OK
- // Disabled code to restore camera location and focus if logging in to default location
- static bool samename = false;
- if (samename)
- {
- // restore old camera pos
- gAgentCamera.setFocusOnAvatar(FALSE, FALSE);
- gAgentCamera.setCameraPosAndFocusGlobal(gSavedSettings.getVector3d("CameraPosOnLogout"), gSavedSettings.getVector3d("FocusPosOnLogout"), LLUUID::null);
- BOOL limit_hit = FALSE;
- gAgentCamera.calcCameraPositionTargetGlobal(&limit_hit);
- if (limit_hit)
- {
- gAgentCamera.setFocusOnAvatar(TRUE, FALSE);
- }
- gAgentCamera.stopCameraAnimation();
- }
- }
- else
- {
- std::string msg;
- switch(start_slurl.getType())
- {
- case LLSLURL::LOCATION:
- {
-
- msg = "AvatarMovedDesired";
- break;
- }
- case LLSLURL::HOME_LOCATION:
- {
- msg = "AvatarMovedHome";
- break;
- }
- default:
- {
- msg = "AvatarMovedLast";
- }
- }
- LLNotificationsUtil::add(msg);
- }
- }
-
- //DEV-17797. get null folder. Any items found here moved to Lost and Found
- LLInventoryModelBackgroundFetch::instance().findLostItems();
-
- LLStartUp::setStartupState( STATE_PRECACHE );
- timeout.reset();
- return FALSE;
- }
-
- if (STATE_PRECACHE == LLStartUp::getStartupState())
- {
- F32 timeout_frac = timeout.getElapsedTimeF32()/PRECACHING_DELAY;
-
- // We now have an inventory skeleton, so if this is a user's first
- // login, we can start setting up their clothing and avatar
- // appearance. This helps to avoid the generic "Ruth" avatar in
- // the orientation island tutorial experience. JC
- if (gAgent.isFirstLogin()
- && !sInitialOutfit.empty() // registration set up an outfit
- && !sInitialOutfitGender.empty() // and a gender
- && isAgentAvatarValid() // can't wear clothes without object
- && !gAgent.isGenderChosen() ) // nothing already loading
- {
- // Start loading the wearables, textures, gestures
- LLStartUp::loadInitialOutfit( sInitialOutfit, sInitialOutfitGender );
- }
-
- // wait precache-delay and for agent's avatar or a lot longer.
- if(((timeout_frac > 1.f) && isAgentAvatarValid())
- || (timeout_frac > 3.f))
- {
- LLStartUp::setStartupState( STATE_WEARABLES_WAIT );
- }
- else
- {
- update_texture_fetch();
- set_startup_status(0.60f + 0.30f * timeout_frac,
- LLTrans::getString("LoginPrecaching"),
- gAgent.mMOTD);
- display_startup();
- if (!LLViewerShaderMgr::sInitialized)
- {
- LLViewerShaderMgr::sInitialized = TRUE;
- LLViewerShaderMgr::instance()->setShaders();
- }
- }
-
- return TRUE;
- }
-
- if (STATE_WEARABLES_WAIT == LLStartUp::getStartupState())
- {
- static LLFrameTimer wearables_timer;
-
- const F32 wearables_time = wearables_timer.getElapsedTimeF32();
- const F32 MAX_WEARABLES_TIME = 10.f;
-
- if (!gAgent.isGenderChosen())
- {
- // No point in waiting for clothing, we don't even
- // know what gender we are. Pop a dialog to ask and
- // proceed to draw the world. JC
- //
- // *NOTE: We might hit this case even if we have an
- // initial outfit, but if the load hasn't started
- // already then something is wrong so fall back
- // to generic outfits. JC
- LLNotificationsUtil::add("WelcomeChooseSex", LLSD(), LLSD(),
- callback_choose_gender);
- LLStartUp::setStartupState( STATE_CLEANUP );
- return TRUE;
- }
-
- if (wearables_time > MAX_WEARABLES_TIME)
- {
- LLNotificationsUtil::add("ClothingLoading");
- LLViewerStats::getInstance()->incStat(LLViewerStats::ST_WEARABLES_TOO_LONG);
- LLStartUp::setStartupState( STATE_CLEANUP );
- return TRUE;
- }
-
- if (gAgent.isFirstLogin())
- {
- // wait for avatar to be completely loaded
- if (isAgentAvatarValid()
- && gAgentAvatarp->isFullyLoaded())
- {
- //llinfos << "avatar fully loaded" << llendl;
- LLStartUp::setStartupState( STATE_CLEANUP );
- return TRUE;
- }
- }
- else
- {
- // OK to just get the wearables
- if ( gAgentWearables.areWearablesLoaded() )
- {
- // We have our clothing, proceed.
- //llinfos << "wearables loaded" << llendl;
- LLStartUp::setStartupState( STATE_CLEANUP );
- return TRUE;
- }
- }
-
- update_texture_fetch();
- set_startup_status(0.9f + 0.1f * wearables_time / MAX_WEARABLES_TIME,
- LLTrans::getString("LoginDownloadingClothing").c_str(),
- gAgent.mMOTD.c_str());
- return TRUE;
- }
-
- if (STATE_CLEANUP == LLStartUp::getStartupState())
- {
- set_startup_status(1.0, "", "");
-
- // Let the map know about the inventory.
- LLFloaterWorldMap* floater_world_map = LLFloaterWorldMap::getInstance();
- if(floater_world_map)
- {
- floater_world_map->observeInventory(&gInventory);
- floater_world_map->observeFriends();
- }
- gViewerWindow->showCursor();
- gViewerWindow->getWindow()->resetBusyCount();
- gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW);
- LL_DEBUGS("AppInit") << "Done releasing bitmap" << LL_ENDL;
- gViewerWindow->setShowProgress(FALSE);
- gViewerWindow->setProgressCancelButtonVisible(FALSE);
-
- // We're not away from keyboard, even though login might have taken
- // a while. JC
- gAgent.clearAFK();
-
- // Have the agent start watching the friends list so we can update proxies
- gAgent.observeFriends();
- if (gSavedSettings.getBOOL("LoginAsGod"))
- {
- gAgent.requestEnterGodMode();
- }
-
- // Start automatic replay if the flag is set.
- if (gSavedSettings.getBOOL("StatsAutoRun") || LLAgentPilot::sReplaySession)
- {
- LLUUID id;
- LL_DEBUGS("AppInit") << "Starting automatic playback" << LL_ENDL;
- gAgentPilot.startPlayback();
- }
-
- show_debug_menus(); // Debug menu visiblity and First Use trigger
-
- // If we've got a startup URL, dispatch it
- LLStartUp::dispatchURL();
-
- // Retrieve information about the land data
- // (just accessing this the first time will fetch it,
- // then the data is cached for the viewer's lifetime)
- LLProductInfoRequestManager::instance();
-
- // *FIX:Mani - What do I do here?
- // Need we really clear the Auth response data?
- // Clean up the userauth stuff.
- // LLUserAuth::getInstance()->reset();
-
- LLStartUp::setStartupState( STATE_STARTED );
-
- // Unmute audio if desired and setup volumes.
- // Unmute audio if desired and setup volumes.
- // This is a not-uncommon crash site, so surround it with
- // llinfos output to aid diagnosis.
- LL_INFOS("AppInit") << "Doing first audio_update_volume..." << LL_ENDL;
- audio_update_volume();
- LL_INFOS("AppInit") << "Done first audio_update_volume." << LL_ENDL;
-
- // reset keyboard focus to sane state of pointing at world
- gFocusMgr.setKeyboardFocus(NULL);
-
-#if 0 // sjb: enable for auto-enabling timer display
- gDebugView->mFastTimerView->setVisible(TRUE);
-#endif
-
- LLAppViewer::instance()->handleLoginComplete();
-
- // reset timers now that we are running "logged in" logic
- LLFastTimer::reset();
-
- LLAgentPicksInfo::getInstance()->requestNumberOfPicks();
-
- LLIMFloater::initIMFloater();
-
- return TRUE;
- }
-
- LL_WARNS("AppInit") << "Reached end of idle_startup for state " << LLStartUp::getStartupState() << LL_ENDL;
- return TRUE;
-}
-
-//
-// local function definition
-//
-
-void login_show()
-{
- LL_INFOS("AppInit") << "Initializing Login Screen" << LL_ENDL;
-
-#ifdef LL_RELEASE_FOR_DOWNLOAD
- BOOL bUseDebugLogin = gSavedSettings.getBOOL("UseDebugLogin");
-#else
- BOOL bUseDebugLogin = TRUE;
-#endif
-
- LLPanelLogin::show( gViewerWindow->getWindowRectScaled(),
- bUseDebugLogin || gSavedSettings.getBOOL("SecondLifeEnterprise"),
- login_callback, NULL );
-
-}
-
-// Callback for when login screen is closed. Option 0 = connect, option 1 = quit.
-void login_callback(S32 option, void *userdata)
-{
- const S32 CONNECT_OPTION = 0;
- const S32 QUIT_OPTION = 1;
-
- if (CONNECT_OPTION == option)
- {
- LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
- return;
- }
- else if (QUIT_OPTION == option) // *TODO: THIS CODE SEEMS TO BE UNREACHABLE!!!!! login_callback is never called with option equal to QUIT_OPTION
- {
- if (!gSavedSettings.getBOOL("RememberPassword"))
- {
- // turn off the setting and write out to disk
- gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile") , TRUE );
- LLUIColorTable::instance().saveUserSettings();
- }
-
- // Next iteration through main loop should shut down the app cleanly.
- LLAppViewer::instance()->userQuit();
-
- if (LLAppViewer::instance()->quitRequested())
- {
- LLPanelLogin::closePanel();
- }
- return;
- }
- else
- {
- LL_WARNS("AppInit") << "Unknown login button clicked" << LL_ENDL;
- }
-}
-
-void show_first_run_dialog()
-{
- LLNotificationsUtil::add("FirstRun", LLSD(), LLSD(), first_run_dialog_callback);
-}
-
-bool first_run_dialog_callback(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (0 == option)
- {
- LL_DEBUGS("AppInit") << "First run dialog cancelling" << LL_ENDL;
- LLWeb::loadURLExternal(LLTrans::getString("create_account_url") );
- }
-
- LLPanelLogin::giveFocus();
- return false;
-}
-
-
-
-void set_startup_status(const F32 frac, const std::string& string, const std::string& msg)
-{
- gViewerWindow->setProgressPercent(frac*100);
- gViewerWindow->setProgressString(string);
-
- gViewerWindow->setProgressMessage(msg);
-}
-
-bool login_alert_status(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- // Buttons
- switch( option )
- {
- case 0: // OK
- break;
- // case 1: // Help
- // LLWeb::loadURL(LLNotifications::instance().getGlobalString("SUPPORT_URL") );
- // break;
- case 2: // Teleport
- // Restart the login process, starting at our home locaton
- LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME));
- LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
- break;
- default:
- LL_WARNS("AppInit") << "Missing case in login_alert_status switch" << LL_ENDL;
- }
-
- LLPanelLogin::giveFocus();
- return false;
-}
-
-
-void use_circuit_callback(void**, S32 result)
-{
- // bail if we're quitting.
- if(LLApp::isExiting()) return;
- if( !gUseCircuitCallbackCalled )
- {
- gUseCircuitCallbackCalled = true;
- if (result)
- {
- // Make sure user knows something bad happened. JC
- LL_WARNS("AppInit") << "Backing up to login screen!" << LL_ENDL;
- LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status);
- reset_login();
- }
- else
- {
- gGotUseCircuitCodeAck = true;
- }
- }
-}
-
-void register_viewer_callbacks(LLMessageSystem* msg)
-{
- msg->setHandlerFuncFast(_PREHASH_LayerData, process_layer_data );
- msg->setHandlerFuncFast(_PREHASH_ImageData, LLViewerTextureList::receiveImageHeader );
- msg->setHandlerFuncFast(_PREHASH_ImagePacket, LLViewerTextureList::receiveImagePacket );
- msg->setHandlerFuncFast(_PREHASH_ObjectUpdate, process_object_update );
- msg->setHandlerFunc("ObjectUpdateCompressed", process_compressed_object_update );
- msg->setHandlerFunc("ObjectUpdateCached", process_cached_object_update );
- msg->setHandlerFuncFast(_PREHASH_ImprovedTerseObjectUpdate, process_terse_object_update_improved );
- msg->setHandlerFunc("SimStats", process_sim_stats);
- msg->setHandlerFuncFast(_PREHASH_HealthMessage, process_health_message );
- msg->setHandlerFuncFast(_PREHASH_EconomyData, process_economy_data);
- msg->setHandlerFunc("RegionInfo", LLViewerRegion::processRegionInfo);
-
- msg->setHandlerFuncFast(_PREHASH_ChatFromSimulator, process_chat_from_simulator);
- msg->setHandlerFuncFast(_PREHASH_KillObject, process_kill_object, NULL);
- msg->setHandlerFuncFast(_PREHASH_SimulatorViewerTimeMessage, process_time_synch, NULL);
- msg->setHandlerFuncFast(_PREHASH_EnableSimulator, process_enable_simulator);
- msg->setHandlerFuncFast(_PREHASH_DisableSimulator, process_disable_simulator);
- msg->setHandlerFuncFast(_PREHASH_KickUser, process_kick_user, NULL);
-
- msg->setHandlerFunc("CrossedRegion", process_crossed_region);
- msg->setHandlerFuncFast(_PREHASH_TeleportFinish, process_teleport_finish);
-
- msg->setHandlerFuncFast(_PREHASH_AlertMessage, process_alert_message);
- msg->setHandlerFunc("AgentAlertMessage", process_agent_alert_message);
- msg->setHandlerFuncFast(_PREHASH_MeanCollisionAlert, process_mean_collision_alert_message, NULL);
- msg->setHandlerFunc("ViewerFrozenMessage", process_frozen_message);
-
- msg->setHandlerFuncFast(_PREHASH_NameValuePair, process_name_value);
- msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair, process_remove_name_value);
- msg->setHandlerFuncFast(_PREHASH_AvatarAnimation, process_avatar_animation);
- msg->setHandlerFuncFast(_PREHASH_AvatarAppearance, process_avatar_appearance);
- msg->setHandlerFunc("AgentCachedTextureResponse", LLAgent::processAgentCachedTextureResponse);
- msg->setHandlerFunc("RebakeAvatarTextures", LLVOAvatarSelf::processRebakeAvatarTextures);
- msg->setHandlerFuncFast(_PREHASH_CameraConstraint, process_camera_constraint);
- msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse, process_avatar_sit_response);
- msg->setHandlerFunc("SetFollowCamProperties", process_set_follow_cam_properties);
- msg->setHandlerFunc("ClearFollowCamProperties", process_clear_follow_cam_properties);
-
- msg->setHandlerFuncFast(_PREHASH_ImprovedInstantMessage, process_improved_im);
- msg->setHandlerFuncFast(_PREHASH_ScriptQuestion, process_script_question);
- msg->setHandlerFuncFast(_PREHASH_ObjectProperties, LLSelectMgr::processObjectProperties, NULL);
- msg->setHandlerFuncFast(_PREHASH_ObjectPropertiesFamily, LLSelectMgr::processObjectPropertiesFamily, NULL);
- msg->setHandlerFunc("ForceObjectSelect", LLSelectMgr::processForceObjectSelect);
-
- msg->setHandlerFuncFast(_PREHASH_MoneyBalanceReply, process_money_balance_reply, NULL);
- msg->setHandlerFuncFast(_PREHASH_CoarseLocationUpdate, LLWorld::processCoarseUpdate, NULL);
- msg->setHandlerFuncFast(_PREHASH_ReplyTaskInventory, LLViewerObject::processTaskInv, NULL);
- msg->setHandlerFuncFast(_PREHASH_DerezContainer, process_derez_container, NULL);
- msg->setHandlerFuncFast(_PREHASH_ScriptRunningReply,
- &LLLiveLSLEditor::processScriptRunningReply);
-
- msg->setHandlerFuncFast(_PREHASH_DeRezAck, process_derez_ack);
-
- msg->setHandlerFunc("LogoutReply", process_logout_reply);
-
- //msg->setHandlerFuncFast(_PREHASH_AddModifyAbility,
- // &LLAgent::processAddModifyAbility);
- //msg->setHandlerFuncFast(_PREHASH_RemoveModifyAbility,
- // &LLAgent::processRemoveModifyAbility);
- msg->setHandlerFuncFast(_PREHASH_AgentDataUpdate,
- &LLAgent::processAgentDataUpdate);
- msg->setHandlerFuncFast(_PREHASH_AgentGroupDataUpdate,
- &LLAgent::processAgentGroupDataUpdate);
- msg->setHandlerFunc("AgentDropGroup",
- &LLAgent::processAgentDropGroup);
- // land ownership messages
- msg->setHandlerFuncFast(_PREHASH_ParcelOverlay,
- LLViewerParcelMgr::processParcelOverlay);
- msg->setHandlerFuncFast(_PREHASH_ParcelProperties,
- LLViewerParcelMgr::processParcelProperties);
- msg->setHandlerFunc("ParcelAccessListReply",
- LLViewerParcelMgr::processParcelAccessListReply);
- msg->setHandlerFunc("ParcelDwellReply",
- LLViewerParcelMgr::processParcelDwellReply);
-
- msg->setHandlerFunc("AvatarPropertiesReply",
- &LLAvatarPropertiesProcessor::processAvatarPropertiesReply);
- msg->setHandlerFunc("AvatarInterestsReply",
- &LLAvatarPropertiesProcessor::processAvatarInterestsReply);
- msg->setHandlerFunc("AvatarGroupsReply",
- &LLAvatarPropertiesProcessor::processAvatarGroupsReply);
- // ratings deprecated
- //msg->setHandlerFuncFast(_PREHASH_AvatarStatisticsReply,
- // LLPanelAvatar::processAvatarStatisticsReply);
- msg->setHandlerFunc("AvatarNotesReply",
- &LLAvatarPropertiesProcessor::processAvatarNotesReply);
- msg->setHandlerFunc("AvatarPicksReply",
- &LLAvatarPropertiesProcessor::processAvatarPicksReply);
- msg->setHandlerFunc("AvatarClassifiedReply",
- &LLAvatarPropertiesProcessor::processAvatarClassifiedsReply);
-
- msg->setHandlerFuncFast(_PREHASH_CreateGroupReply,
- LLGroupMgr::processCreateGroupReply);
- msg->setHandlerFuncFast(_PREHASH_JoinGroupReply,
- LLGroupMgr::processJoinGroupReply);
- msg->setHandlerFuncFast(_PREHASH_EjectGroupMemberReply,
- LLGroupMgr::processEjectGroupMemberReply);
- msg->setHandlerFuncFast(_PREHASH_LeaveGroupReply,
- LLGroupMgr::processLeaveGroupReply);
- msg->setHandlerFuncFast(_PREHASH_GroupProfileReply,
- LLGroupMgr::processGroupPropertiesReply);
-
- // ratings deprecated
- // msg->setHandlerFuncFast(_PREHASH_ReputationIndividualReply,
- // LLFloaterRate::processReputationIndividualReply);
-
- msg->setHandlerFuncFast(_PREHASH_AgentWearablesUpdate,
- LLAgentWearables::processAgentInitialWearablesUpdate );
-
- msg->setHandlerFunc("ScriptControlChange",
- LLAgent::processScriptControlChange );
-
- msg->setHandlerFuncFast(_PREHASH_ViewerEffect, LLHUDManager::processViewerEffect);
-
- msg->setHandlerFuncFast(_PREHASH_GrantGodlikePowers, process_grant_godlike_powers);
-
- msg->setHandlerFuncFast(_PREHASH_GroupAccountSummaryReply,
- LLPanelGroupLandMoney::processGroupAccountSummaryReply);
- msg->setHandlerFuncFast(_PREHASH_GroupAccountDetailsReply,
- LLPanelGroupLandMoney::processGroupAccountDetailsReply);
- msg->setHandlerFuncFast(_PREHASH_GroupAccountTransactionsReply,
- LLPanelGroupLandMoney::processGroupAccountTransactionsReply);
-
- msg->setHandlerFuncFast(_PREHASH_UserInfoReply,
- process_user_info_reply);
-
- msg->setHandlerFunc("RegionHandshake", process_region_handshake, NULL);
-
- msg->setHandlerFunc("TeleportStart", process_teleport_start );
- msg->setHandlerFunc("TeleportProgress", process_teleport_progress);
- msg->setHandlerFunc("TeleportFailed", process_teleport_failed, NULL);
- msg->setHandlerFunc("TeleportLocal", process_teleport_local, NULL);
-
- msg->setHandlerFunc("ImageNotInDatabase", LLViewerTextureList::processImageNotInDatabase, NULL);
-
- msg->setHandlerFuncFast(_PREHASH_GroupMembersReply,
- LLGroupMgr::processGroupMembersReply);
- msg->setHandlerFunc("GroupRoleDataReply",
- LLGroupMgr::processGroupRoleDataReply);
- msg->setHandlerFunc("GroupRoleMembersReply",
- LLGroupMgr::processGroupRoleMembersReply);
- msg->setHandlerFunc("GroupTitlesReply",
- LLGroupMgr::processGroupTitlesReply);
- // Special handler as this message is sometimes used for group land.
- msg->setHandlerFunc("PlacesReply", process_places_reply);
- msg->setHandlerFunc("GroupNoticesListReply", LLPanelGroupNotices::processGroupNoticesListReply);
-
- msg->setHandlerFunc("AvatarPickerReply", LLFloaterAvatarPicker::processAvatarPickerReply);
-
- msg->setHandlerFunc("MapBlockReply", LLWorldMapMessage::processMapBlockReply);
- msg->setHandlerFunc("MapItemReply", LLWorldMapMessage::processMapItemReply);
- msg->setHandlerFunc("EventInfoReply", LLEventNotifier::processEventInfoReply);
-
- msg->setHandlerFunc("PickInfoReply", &LLAvatarPropertiesProcessor::processPickInfoReply);
-// msg->setHandlerFunc("ClassifiedInfoReply", LLPanelClassified::processClassifiedInfoReply);
- msg->setHandlerFunc("ClassifiedInfoReply", LLAvatarPropertiesProcessor::processClassifiedInfoReply);
- msg->setHandlerFunc("ParcelInfoReply", LLRemoteParcelInfoProcessor::processParcelInfoReply);
- msg->setHandlerFunc("ScriptDialog", process_script_dialog);
- msg->setHandlerFunc("LoadURL", process_load_url);
- msg->setHandlerFunc("ScriptTeleportRequest", process_script_teleport_request);
- msg->setHandlerFunc("EstateCovenantReply", process_covenant_reply);
-
- // calling cards
- msg->setHandlerFunc("OfferCallingCard", process_offer_callingcard);
- msg->setHandlerFunc("AcceptCallingCard", process_accept_callingcard);
- msg->setHandlerFunc("DeclineCallingCard", process_decline_callingcard);
-
- msg->setHandlerFunc("ParcelObjectOwnersReply", LLPanelLandObjects::processParcelObjectOwnersReply);
-
- msg->setHandlerFunc("InitiateDownload", process_initiate_download);
- msg->setHandlerFunc("LandStatReply", LLFloaterTopObjects::handle_land_reply);
- msg->setHandlerFunc("GenericMessage", process_generic_message);
-
- msg->setHandlerFuncFast(_PREHASH_FeatureDisabled, process_feature_disabled_message);
-}
-
-void asset_callback_nothing(LLVFS*, const LLUUID&, LLAssetType::EType, void*, S32)
-{
- // nothing
-}
-
-// *HACK: Must match name in Library or agent inventory
-const std::string ROOT_GESTURES_FOLDER = "Gestures";
-const std::string COMMON_GESTURES_FOLDER = "Common Gestures";
-const std::string MALE_GESTURES_FOLDER = "Male Gestures";
-const std::string FEMALE_GESTURES_FOLDER = "Female Gestures";
-const std::string SPEECH_GESTURES_FOLDER = "Speech Gestures";
-const std::string OTHER_GESTURES_FOLDER = "Other Gestures";
-const S32 OPT_CLOSED_WINDOW = -1;
-const S32 OPT_MALE = 0;
-const S32 OPT_FEMALE = 1;
-const S32 OPT_TRUST_CERT = 0;
-const S32 OPT_CANCEL_TRUST = 1;
-
-bool callback_choose_gender(const LLSD& notification, const LLSD& response)
-{
-
- // These defaults are returned from the server on login. They are set in login.xml.
- // If no default is returned from the server, they are retrieved from settings.xml.
-
- S32 option = LLNotification::getSelectedOption(notification, response);
- switch(option)
- {
- case OPT_MALE:
- LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultMaleAvatar"), "male" );
- break;
-
- case OPT_FEMALE:
- case OPT_CLOSED_WINDOW:
- default:
- LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultFemaleAvatar"), "female" );
- break;
- }
- return false;
-}
-
-void LLStartUp::copyLibraryGestures(const std::string& same_gender_gestures)
-{
- llinfos << "Copying library gestures" << llendl;
-
- // Copy gestures
- LLUUID lib_gesture_cat_id =
- gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE,false,true);
- if (lib_gesture_cat_id.isNull())
- {
- llwarns << "Unable to copy gestures, source category not found" << llendl;
- }
- LLUUID dst_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE);
-
- std::vector<std::string> gesture_folders_to_copy;
- gesture_folders_to_copy.push_back(MALE_GESTURES_FOLDER);
- gesture_folders_to_copy.push_back(FEMALE_GESTURES_FOLDER);
- gesture_folders_to_copy.push_back(COMMON_GESTURES_FOLDER);
- gesture_folders_to_copy.push_back(SPEECH_GESTURES_FOLDER);
- gesture_folders_to_copy.push_back(OTHER_GESTURES_FOLDER);
-
- for(std::vector<std::string>::iterator it = gesture_folders_to_copy.begin();
- it != gesture_folders_to_copy.end();
- ++it)
- {
- std::string& folder_name = *it;
-
- LLPointer<LLInventoryCallback> cb(NULL);
-
- if (folder_name == same_gender_gestures ||
- folder_name == COMMON_GESTURES_FOLDER ||
- folder_name == OTHER_GESTURES_FOLDER)
- {
- cb = new ActivateGestureCallback;
- }
-
-
- LLUUID cat_id = findDescendentCategoryIDByName(lib_gesture_cat_id,folder_name);
- if (cat_id.isNull())
- {
- llwarns << "failed to find gesture folder for " << folder_name << llendl;
- }
- else
- {
- llinfos << "initiating fetch and copy for " << folder_name << " cat_id " << cat_id << llendl;
- LLAppearanceMgr* app_mgr = LLAppearanceMgr::getInstance();
- callAfterCategoryFetch(cat_id,
- boost::bind(&LLAppearanceMgr::shallowCopyCategory,
- app_mgr,
- cat_id,
- dst_id,
- cb));
- }
- }
-}
-
-void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name,
- const std::string& gender_name )
-{
- llinfos << "starting" << llendl;
-
- // Not going through the processAgentInitialWearables path, so need to set this here.
- LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true);
- // Initiate creation of COF, since we're also bypassing that.
- gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
-
- S32 gender = 0;
- std::string same_gender_gestures;
- if (gender_name == "male")
- {
- gender = OPT_MALE;
- same_gender_gestures = MALE_GESTURES_FOLDER;
- }
- else
- {
- gender = OPT_FEMALE;
- same_gender_gestures = FEMALE_GESTURES_FOLDER;
- }
-
- // try to find the outfit - if not there, create some default
- // wearables.
- LLUUID cat_id = findDescendentCategoryIDByName(
- gInventory.getLibraryRootFolderID(),
- outfit_folder_name);
- if (cat_id.isNull())
- {
- gAgentWearables.createStandardWearables(gender);
- }
- else
- {
- sWearablesLoadedCon = gAgentWearables.addLoadedCallback(LLStartUp::saveInitialOutfit);
-
- bool do_copy = true;
- bool do_append = false;
- LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
- LLAppearanceMgr::instance().wearInventoryCategory(cat, do_copy, do_append);
- }
-
- // Copy gestures
- copyLibraryGestures(same_gender_gestures);
-
- // This is really misnamed -- it means we have started loading
- // an outfit/shape that will give the avatar a gender eventually. JC
- gAgent.setGenderChosen(TRUE);
-
-}
-
-//static
-void LLStartUp::saveInitialOutfit()
-{
- if (sInitialOutfit.empty()) return;
-
- if (sWearablesLoadedCon.connected())
- {
- sWearablesLoadedCon.disconnect();
- }
- LLAppearanceMgr::getInstance()->makeNewOutfitLinks(sInitialOutfit,false);
-}
-
-std::string& LLStartUp::getInitialOutfitName()
-{
- return sInitialOutfit;
-}
-
-// Loads a bitmap to display during load
-void init_start_screen(S32 location_id)
-{
- if (gStartTexture.notNull())
- {
- gStartTexture = NULL;
- LL_INFOS("AppInit") << "re-initializing start screen" << LL_ENDL;
- }
-
- LL_DEBUGS("AppInit") << "Loading startup bitmap..." << LL_ENDL;
-
- std::string temp_str = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter();
-
- if ((S32)START_LOCATION_ID_LAST == location_id)
- {
- temp_str += SCREEN_LAST_FILENAME;
- }
- else
- {
- temp_str += SCREEN_HOME_FILENAME;
- }
-
- LLPointer<LLImageBMP> start_image_bmp = new LLImageBMP;
-
- // Turn off start screen to get around the occasional readback
- // driver bug
- if(!gSavedSettings.getBOOL("UseStartScreen"))
- {
- LL_INFOS("AppInit") << "Bitmap load disabled" << LL_ENDL;
- return;
- }
- else if(!start_image_bmp->load(temp_str) )
- {
- LL_WARNS("AppInit") << "Bitmap load failed" << LL_ENDL;
- return;
- }
-
- gStartImageWidth = start_image_bmp->getWidth();
- gStartImageHeight = start_image_bmp->getHeight();
-
- LLPointer<LLImageRaw> raw = new LLImageRaw;
- if (!start_image_bmp->decode(raw, 0.0f))
- {
- LL_WARNS("AppInit") << "Bitmap decode failed" << LL_ENDL;
- gStartTexture = NULL;
- return;
- }
-
- raw->expandToPowerOfTwo();
- gStartTexture = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE) ;
-}
-
-
-// frees the bitmap
-void release_start_screen()
-{
- LL_DEBUGS("AppInit") << "Releasing bitmap..." << LL_ENDL;
- gStartTexture = NULL;
-}
-
-
-// static
-std::string LLStartUp::startupStateToString(EStartupState state)
-{
-#define RTNENUM(E) case E: return #E
- switch(state){
- RTNENUM( STATE_FIRST );
- RTNENUM( STATE_BROWSER_INIT );
- RTNENUM( STATE_LOGIN_SHOW );
- RTNENUM( STATE_LOGIN_WAIT );
- RTNENUM( STATE_LOGIN_CLEANUP );
- RTNENUM( STATE_LOGIN_AUTH_INIT );
- RTNENUM( STATE_LOGIN_CURL_UNSTUCK );
- RTNENUM( STATE_LOGIN_PROCESS_RESPONSE );
- RTNENUM( STATE_WORLD_INIT );
- RTNENUM( STATE_MULTIMEDIA_INIT );
- RTNENUM( STATE_FONT_INIT );
- RTNENUM( STATE_SEED_GRANTED_WAIT );
- RTNENUM( STATE_SEED_CAP_GRANTED );
- RTNENUM( STATE_WORLD_WAIT );
- RTNENUM( STATE_AGENT_SEND );
- RTNENUM( STATE_AGENT_WAIT );
- RTNENUM( STATE_INVENTORY_SEND );
- RTNENUM( STATE_MISC );
- RTNENUM( STATE_PRECACHE );
- RTNENUM( STATE_WEARABLES_WAIT );
- RTNENUM( STATE_CLEANUP );
- RTNENUM( STATE_STARTED );
- default:
- return llformat("(state #%d)", state);
- }
-#undef RTNENUM
-}
-
-// static
-void LLStartUp::setStartupState( EStartupState state )
-{
- LL_INFOS("AppInit") << "Startup state changing from " <<
- getStartupStateString() << " to " <<
- startupStateToString(state) << LL_ENDL;
- gStartupState = state;
- postStartupState();
-}
-
-void LLStartUp::postStartupState()
-{
- LLSD stateInfo;
- stateInfo["str"] = getStartupStateString();
- stateInfo["enum"] = gStartupState;
- sStateWatcher->post(stateInfo);
-}
-
-
-void reset_login()
-{
- gAgentWearables.cleanup();
- gAgentCamera.cleanup();
- gAgent.cleanup();
- LLWorld::getInstance()->destroyClass();
-
- LLStartUp::setStartupState( STATE_LOGIN_SHOW );
-
- if ( gViewerWindow )
- { // Hide menus and normal buttons
- gViewerWindow->setNormalControlsVisible( FALSE );
- gLoginMenuBarView->setVisible( TRUE );
- gLoginMenuBarView->setEnabled( TRUE );
- }
-
- // Hide any other stuff
- LLFloaterReg::hideVisibleInstances();
-}
-
-//---------------------------------------------------------------------------
-
-// Initialize all plug-ins except the web browser (which was initialized
-// early, before the login screen). JC
-void LLStartUp::multimediaInit()
-{
- LL_DEBUGS("AppInit") << "Initializing Multimedia...." << LL_ENDL;
- std::string msg = LLTrans::getString("LoginInitializingMultimedia");
- set_startup_status(0.42f, msg.c_str(), gAgent.mMOTD.c_str());
- display_startup();
-
- // LLViewerMedia::initClass();
- LLViewerParcelMedia::initClass();
-}
-
-void LLStartUp::fontInit()
-{
- LL_DEBUGS("AppInit") << "Initializing fonts...." << LL_ENDL;
- std::string msg = LLTrans::getString("LoginInitializingFonts");
- set_startup_status(0.45f, msg.c_str(), gAgent.mMOTD.c_str());
- display_startup();
-
- LLFontGL::loadDefaultFonts();
-}
-
-void LLStartUp::initNameCache()
-{
- // Can be called multiple times
- if ( gCacheName ) return;
-
- gCacheName = new LLCacheName(gMessageSystem);
- gCacheName->addObserver(&callback_cache_name);
- gCacheName->localizeCacheName("waiting", LLTrans::getString("AvatarNameWaiting"));
- gCacheName->localizeCacheName("nobody", LLTrans::getString("AvatarNameNobody"));
- gCacheName->localizeCacheName("none", LLTrans::getString("GroupNameNone"));
- // Load stored cache if possible
- LLAppViewer::instance()->loadNameCache();
-
- // Start cache in not-running state until we figure out if we have
- // capabilities for display name lookup
- LLAvatarNameCache::initClass(false);
- LLAvatarNameCache::setUseDisplayNames(gSavedSettings.getBOOL("UseDisplayNames"));
-}
-
-void LLStartUp::cleanupNameCache()
-{
- LLAvatarNameCache::cleanupClass();
-
- delete gCacheName;
- gCacheName = NULL;
-}
-
-bool LLStartUp::dispatchURL()
-{
- // ok, if we've gotten this far and have a startup URL
- if (!getStartSLURL().isValid())
- {
- return false;
- }
- if(getStartSLURL().getType() != LLSLURL::APP)
- {
-
- // If we started with a location, but we're already
- // at that location, don't pop dialogs open.
- LLVector3 pos = gAgent.getPositionAgent();
- LLVector3 slurlpos = getStartSLURL().getPosition();
- F32 dx = pos.mV[VX] - slurlpos.mV[VX];
- F32 dy = pos.mV[VY] - slurlpos.mV[VY];
- const F32 SLOP = 2.f; // meters
-
- if( getStartSLURL().getRegion() != gAgent.getRegion()->getName()
- || (dx*dx > SLOP*SLOP)
- || (dy*dy > SLOP*SLOP) )
- {
- LLURLDispatcher::dispatch(getStartSLURL().getSLURLString(),
- NULL, false);
- }
- return true;
- }
- return false;
-}
-
-void LLStartUp::setStartSLURL(const LLSLURL& slurl)
-{
- sStartSLURL = slurl;
- switch(slurl.getType())
- {
- case LLSLURL::HOME_LOCATION:
- {
- gSavedSettings.setString("LoginLocation", LLSLURL::SIM_LOCATION_HOME);
- break;
- }
- case LLSLURL::LAST_LOCATION:
- {
- gSavedSettings.setString("LoginLocation", LLSLURL::SIM_LOCATION_LAST);
- break;
- }
- default:
- LLGridManager::getInstance()->setGridChoice(slurl.getGrid());
- break;
- }
-}
-
-bool login_alert_done(const LLSD& notification, const LLSD& response)
-{
- LLPanelLogin::giveFocus();
- return false;
-}
-
-// parse the certificate information into args for the
-// certificate notifications
-LLSD transform_cert_args(LLPointer<LLCertificate> cert)
-{
- LLSD args = LLSD::emptyMap();
- std::string value;
- LLSD cert_info;
- cert->getLLSD(cert_info);
- // convert all of the elements in the cert into
- // args for the xml dialog, so we have flexability to
- // display various parts of the cert by only modifying
- // the cert alert dialog xml.
- for(LLSD::map_iterator iter = cert_info.beginMap();
- iter != cert_info.endMap();
- iter++)
- {
- // key usage and extended key usage
- // are actually arrays, and we want to format them as comma separated
- // strings, so special case those.
- LLSDSerialize::toXML(cert_info[iter->first], std::cout);
- if((iter->first== std::string(CERT_KEY_USAGE)) |
- (iter->first == std::string(CERT_EXTENDED_KEY_USAGE)))
- {
- value = "";
- LLSD usage = cert_info[iter->first];
- for (LLSD::array_iterator usage_iter = usage.beginArray();
- usage_iter != usage.endArray();
- usage_iter++)
- {
-
- if(usage_iter != usage.beginArray())
- {
- value += ", ";
- }
-
- value += (*usage_iter).asString();
- }
-
- }
- else
- {
- value = iter->second.asString();
- }
-
- std::string name = iter->first;
- std::transform(name.begin(), name.end(), name.begin(),
- (int(*)(int))toupper);
- args[name.c_str()] = value;
- }
- return args;
-}
-
-
-// when we handle a cert error, give focus back to the login panel
-void general_cert_done(const LLSD& notification, const LLSD& response)
-{
- LLStartUp::setStartupState( STATE_LOGIN_SHOW );
- LLPanelLogin::giveFocus();
-}
-
-// check to see if the user wants to trust the cert.
-// if they do, add it to the cert store and
-void trust_cert_done(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotification::getSelectedOption(notification, response);
- switch(option)
- {
- case OPT_TRUST_CERT:
- {
- LLPointer<LLCertificate> cert = gSecAPIHandler->getCertificate(notification["payload"]["certificate"]);
- LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore(gSavedSettings.getString("CertStore"));
- store->add(cert);
- store->save();
- LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
- break;
- }
- case OPT_CANCEL_TRUST:
- reset_login();
- gSavedSettings.setBOOL("AutoLogin", FALSE);
- LLStartUp::setStartupState( STATE_LOGIN_SHOW );
- default:
- LLPanelLogin::giveFocus();
- break;
- }
-
-}
-
-void apply_udp_blacklist(const std::string& csv)
-{
-
- std::string::size_type start = 0;
- std::string::size_type comma = 0;
- do
- {
- comma = csv.find(",", start);
- if (comma == std::string::npos)
- {
- comma = csv.length();
- }
- std::string item(csv, start, comma-start);
-
- lldebugs << "udp_blacklist " << item << llendl;
- gMessageSystem->banUdpMessage(item);
-
- start = comma + 1;
-
- }
- while(comma < csv.length());
-
-}
-
-bool process_login_success_response()
-{
- LLSD response = LLLoginInstance::getInstance()->getResponse();
-
- std::string text(response["udp_blacklist"]);
- if(!text.empty())
- {
- apply_udp_blacklist(text);
- }
-
- // unpack login data needed by the application
- text = response["agent_id"].asString();
- if(!text.empty()) gAgentID.set(text);
- gDebugInfo["AgentID"] = text;
-
- // Agent id needed for parcel info request in LLUrlEntryParcel
- // to resolve parcel name.
- LLUrlEntryParcel::setAgentID(gAgentID);
-
- text = response["session_id"].asString();
- if(!text.empty()) gAgentSessionID.set(text);
- gDebugInfo["SessionID"] = text;
-
- // Session id needed for parcel info request in LLUrlEntryParcel
- // to resolve parcel name.
- LLUrlEntryParcel::setSessionID(gAgentSessionID);
-
- text = response["secure_session_id"].asString();
- if(!text.empty()) gAgent.mSecureSessionID.set(text);
-
- // if the response contains a display name, use that,
- // otherwise if the response contains a first and/or last name,
- // use those. Otherwise use the credential identifier
-
- gDisplayName = "";
- if (response.has("display_name"))
- {
- gDisplayName.assign(response["display_name"].asString());
- if(!gDisplayName.empty())
- {
- // Remove quotes from string. Login.cgi sends these to force
- // names that look like numbers into strings.
- LLStringUtil::replaceChar(gDisplayName, '"', ' ');
- LLStringUtil::trim(gDisplayName);
- }
- }
- if(gDisplayName.empty())
- {
- if(response.has("first_name"))
- {
- gDisplayName.assign(response["first_name"].asString());
- LLStringUtil::replaceChar(gDisplayName, '"', ' ');
- LLStringUtil::trim(gDisplayName);
- }
- if(response.has("last_name"))
- {
- text.assign(response["last_name"].asString());
- LLStringUtil::replaceChar(text, '"', ' ');
- LLStringUtil::trim(text);
- if(!gDisplayName.empty())
- {
- gDisplayName += " ";
- }
- gDisplayName += text;
- }
- }
- if(gDisplayName.empty())
- {
- gDisplayName.assign(gUserCredential->asString());
- }
-
- // this is their actual ability to access content
- text = response["agent_access_max"].asString();
- if (!text.empty())
- {
- // agent_access can be 'A', 'M', and 'PG'.
- gAgent.setMaturity(text[0]);
- }
-
- // this is the value of their preference setting for that content
- // which will always be <= agent_access_max
- text = response["agent_region_access"].asString();
- if (!text.empty())
- {
- U32 preferredMaturity = (U32)LLAgent::convertTextToMaturity(text[0]);
-
- gSavedSettings.setU32("PreferredMaturity", preferredMaturity);
- }
- // During the AO transition, this flag will be true. Then the flag will
- // go away. After the AO transition, this code and all the code that
- // uses it can be deleted.
- text = response["ao_transition"].asString();
- if (!text.empty())
- {
- if (text == "1")
- {
- gAgent.setAOTransition();
- }
- }
-
- text = response["start_location"].asString();
- if(!text.empty())
- {
- gAgentStartLocation.assign(text);
- }
-
- text = response["circuit_code"].asString();
- if(!text.empty())
- {
- gMessageSystem->mOurCircuitCode = strtoul(text.c_str(), NULL, 10);
- }
- std::string sim_ip_str = response["sim_ip"];
- std::string sim_port_str = response["sim_port"];
- if(!sim_ip_str.empty() && !sim_port_str.empty())
- {
- U32 sim_port = strtoul(sim_port_str.c_str(), NULL, 10);
- gFirstSim.set(sim_ip_str, sim_port);
- if (gFirstSim.isOk())
- {
- gMessageSystem->enableCircuit(gFirstSim, TRUE);
- }
- }
- std::string region_x_str = response["region_x"];
- std::string region_y_str = response["region_y"];
- if(!region_x_str.empty() && !region_y_str.empty())
- {
- U32 region_x = strtoul(region_x_str.c_str(), NULL, 10);
- U32 region_y = strtoul(region_y_str.c_str(), NULL, 10);
- gFirstSimHandle = to_region_handle(region_x, region_y);
- }
-
- const std::string look_at_str = response["look_at"];
- if (!look_at_str.empty())
- {
- size_t len = look_at_str.size();
- LLMemoryStream mstr((U8*)look_at_str.c_str(), len);
- LLSD sd = LLSDSerialize::fromNotation(mstr, len);
- gAgentStartLookAt = ll_vector3_from_sd(sd);
- }
-
- text = response["seed_capability"].asString();
- if (!text.empty()) gFirstSimSeedCap = text;
-
- text = response["seconds_since_epoch"].asString();
- if(!text.empty())
- {
- U32 server_utc_time = strtoul(text.c_str(), NULL, 10);
- if(server_utc_time)
- {
- time_t now = time(NULL);
- gUTCOffset = (server_utc_time - now);
- }
- }
-
- // this is the base used to construct help URLs
- text = response["help_url_format"].asString();
- if (!text.empty())
- {
- // replace the default help URL format
- gSavedSettings.setString("HelpURLFormat",text);
-
- // don't fall back to Standalone's pre-connection static help
- gSavedSettings.setBOOL("HelpUseLocal", false);
- }
-
- std::string home_location = response["home"];
- if(!home_location.empty())
- {
- size_t len = home_location.size();
- LLMemoryStream mstr((U8*)home_location.c_str(), len);
- LLSD sd = LLSDSerialize::fromNotation(mstr, len);
- S32 region_x = sd["region_handle"][0].asInteger();
- S32 region_y = sd["region_handle"][1].asInteger();
- U64 region_handle = to_region_handle(region_x, region_y);
- LLVector3 position = ll_vector3_from_sd(sd["position"]);
- gAgent.setHomePosRegion(region_handle, position);
- }
-
- gAgent.mMOTD.assign(response["message"]);
-
- // Options...
- // Each 'option' is an array of submaps.
- // It appears that we only ever use the first element of the array.
- LLUUID inv_root_folder_id = response["inventory-root"][0]["folder_id"];
- if(inv_root_folder_id.notNull())
- {
- gInventory.setRootFolderID(inv_root_folder_id);
- //gInventory.mock(gAgent.getInventoryRootID());
- }
-
- LLSD login_flags = response["login-flags"][0];
- if(login_flags.size())
- {
- std::string flag = login_flags["ever_logged_in"];
- if(!flag.empty())
- {
- gAgent.setFirstLogin((flag == "N") ? TRUE : FALSE);
- }
-
- /* Flag is currently ignored by the viewer.
- flag = login_flags["stipend_since_login"];
- if(flag == "Y")
- {
- stipend_since_login = true;
- }
- */
-
- flag = login_flags["gendered"].asString();
- if(flag == "Y")
- {
- gAgent.setGenderChosen(TRUE);
- }
-
- bool pacific_daylight_time = false;
- flag = login_flags["daylight_savings"].asString();
- if(flag == "Y")
- {
- pacific_daylight_time = (flag == "Y");
- }
-
- //setup map of datetime strings to codes and slt & local time offset from utc
- LLStringOps::setupDatetimeInfo(pacific_daylight_time);
- }
-
- // set up the voice configuration. Ultimately, we should pass this up as part of each voice
- // channel if we need to move to multiple voice servers per grid.
- LLSD voice_config_info = response["voice-config"];
- if(voice_config_info.has("VoiceServerType"))
- {
- gSavedSettings.setString("VoiceServerType", voice_config_info["VoiceServerType"].asString());
- }
-
- // Request the map server url
- std::string map_server_url = response["map-server-url"];
- if(!map_server_url.empty())
- {
- // We got an answer from the grid -> use that for map for the current session
- gSavedSettings.setString("CurrentMapServerURL", map_server_url);
- LL_INFOS("LLStartup") << "map-server-url : we got an answer from the grid : " << map_server_url << LL_ENDL;
- }
- else
- {
- // No answer from the grid -> use the default setting for current session
- map_server_url = gSavedSettings.getString("MapServerURL");
- gSavedSettings.setString("CurrentMapServerURL", map_server_url);
- LL_INFOS("LLStartup") << "map-server-url : no map-server-url answer, we use the default setting for the map : " << map_server_url << LL_ENDL;
- }
-
- // Default male and female avatars allowing the user to choose their avatar on first login.
- // These may be passed up by SLE to allow choice of enterprise avatars instead of the standard
- // "new ruth." Not to be confused with 'initial-outfit' below
- LLSD newuser_config = response["newuser-config"][0];
- if(newuser_config.has("DefaultFemaleAvatar"))
- {
- gSavedSettings.setString("DefaultFemaleAvatar", newuser_config["DefaultFemaleAvatar"].asString());
- }
- if(newuser_config.has("DefaultMaleAvatar"))
- {
- gSavedSettings.setString("DefaultMaleAvatar", newuser_config["DefaultMaleAvatar"].asString());
- }
-
- // Initial outfit for the user.
- // QUESTION: Why can't we simply simply set the users outfit directly
- // from a web page into the user info on the server? - Roxie
- LLSD initial_outfit = response["initial-outfit"][0];
- if(initial_outfit.size())
- {
- std::string flag = initial_outfit["folder_name"];
- if(!flag.empty())
- {
- // Initial outfit is a folder in your inventory,
- // must be an exact folder-name match.
- sInitialOutfit = flag;
- }
-
- flag = initial_outfit["gender"].asString();
- if(!flag.empty())
- {
- sInitialOutfitGender = flag;
- }
- }
-
- LLSD global_textures = response["global-textures"][0];
- if(global_textures.size())
- {
- // Extract sun and moon texture IDs. These are used
- // in the LLVOSky constructor, but I can't figure out
- // how to pass them in. JC
- LLUUID id = global_textures["sun_texture_id"];
- if(id.notNull())
- {
- gSunTextureID = id;
- }
-
- id = global_textures["moon_texture_id"];
- if(id.notNull())
- {
- gMoonTextureID = id;
- }
-
- id = global_textures["cloud_texture_id"];
- if(id.notNull())
- {
- gCloudTextureID = id;
- }
- }
-
- // Set the location of the snapshot sharing config endpoint
- std::string snapshot_config_url = response["snapshot_config_url"];
- if(!snapshot_config_url.empty())
- {
- gSavedSettings.setString("SnapshotConfigURL", snapshot_config_url);
- }
-
- // Start the process of fetching the OpenID session cookie for this user login
- std::string openid_url = response["openid_url"];
- if(!openid_url.empty())
- {
- std::string openid_token = response["openid_token"];
- LLViewerMedia::openIDSetup(openid_url, openid_token);
- }
-
- if(response.has("max-agent-groups")) {
- std::string max_agent_groups(response["max-agent-groups"]);
- gMaxAgentGroups = atoi(max_agent_groups.c_str());
- LL_INFOS("LLStartup") << "gMaxAgentGroups read from login.cgi: "
- << gMaxAgentGroups << LL_ENDL;
- }
- else {
- gMaxAgentGroups = DEFAULT_MAX_AGENT_GROUPS;
- LL_INFOS("LLStartup") << "using gMaxAgentGroups default: "
- << gMaxAgentGroups << LL_ENDL;
- }
-
- bool success = false;
- // JC: gesture loading done below, when we have an asset system
- // in place. Don't delete/clear gUserCredentials until then.
- if(gAgentID.notNull()
- && gAgentSessionID.notNull()
- && gMessageSystem->mOurCircuitCode
- && gFirstSim.isOk()
- && gInventory.getRootFolderID().notNull())
- {
- success = true;
- }
-
- return success;
-}
-
-void transition_back_to_login_panel(const std::string& emsg)
-{
- if (gNoRender)
- {
- LL_WARNS("AppInit") << "Failed to login!" << LL_ENDL;
- LL_WARNS("AppInit") << emsg << LL_ENDL;
- exit(0);
- }
-
- // Bounce back to the login screen.
- reset_login(); // calls LLStartUp::setStartupState( STATE_LOGIN_SHOW );
- gSavedSettings.setBOOL("AutoLogin", FALSE);
-}
+/** + * @file llstartup.cpp + * @brief startup routines. + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llstartup.h" + +#if LL_WINDOWS +# include <process.h> // _spawnl() +#else +# include <sys/stat.h> // mkdir() +#endif + +#include "llviewermedia_streamingaudio.h" +#include "llaudioengine.h" + +#ifdef LL_FMOD +# include "llaudioengine_fmod.h" +#endif + +#ifdef LL_OPENAL +#include "llaudioengine_openal.h" +#endif + +#include "llares.h" +#include "llavatarnamecache.h" +#include "lllandmark.h" +#include "llcachename.h" +#include "lldir.h" +#include "llerrorcontrol.h" +#include "llfloaterreg.h" +#include "llfocusmgr.h" +#include "llhttpsender.h" +#include "llimfloater.h" +#include "lllocationhistory.h" +#include "llimageworker.h" + +#include "llloginflags.h" +#include "llmd5.h" +#include "llmemorystream.h" +#include "llmessageconfig.h" +#include "llmoveview.h" +#include "llnearbychat.h" +#include "llnotifications.h" +#include "llnotificationsutil.h" +#include "llteleporthistory.h" +#include "llregionhandle.h" +#include "llsd.h" +#include "llsdserialize.h" +#include "llsdutil_math.h" +#include "llsecondlifeurls.h" +#include "llstring.h" +#include "lluserrelations.h" +#include "llversioninfo.h" +#include "llviewercontrol.h" +#include "llvfs.h" +#include "llxorcipher.h" // saved password, MAC address +#include "llwindow.h" +#include "imageids.h" +#include "message.h" +#include "v3math.h" + +#include "llagent.h" +#include "llagentcamera.h" +#include "llagentpicksinfo.h" +#include "llagentwearables.h" +#include "llagentpilot.h" +#include "llfloateravatarpicker.h" +#include "llcallbacklist.h" +#include "llcallingcard.h" +#include "llconsole.h" +#include "llcontainerview.h" +#include "lldebugview.h" +#include "lldrawable.h" +#include "lleventnotifier.h" +#include "llface.h" +#include "llfeaturemanager.h" +//#include "llfirstuse.h" +#include "llfloaterhud.h" +#include "llfloaterland.h" +#include "llfloaterpreference.h" +#include "llfloatertopobjects.h" +#include "llfloaterworldmap.h" +#include "llgesturemgr.h" +#include "llgroupmgr.h" +#include "llhudeffecttrail.h" +#include "llhudmanager.h" +#include "llhttpclient.h" +#include "llimagebmp.h" +#include "llinventorybridge.h" +#include "llinventorymodel.h" +#include "llinventorymodelbackgroundfetch.h" +#include "llkeyboard.h" +#include "llloginhandler.h" // gLoginHandler, SLURL support +#include "lllogininstance.h" // Host the login module. +#include "llpanellogin.h" +#include "llmutelist.h" +#include "llavatarpropertiesprocessor.h" +#include "llpanelclassified.h" +#include "llpanelpick.h" +#include "llpanelgrouplandmoney.h" +#include "llpanelgroupnotices.h" +#include "llpreview.h" +#include "llpreviewscript.h" +#include "llproductinforequest.h" +#include "llsecondlifeurls.h" +#include "llselectmgr.h" +#include "llsky.h" +#include "llsidetray.h" +#include "llstatview.h" +#include "llstatusbar.h" // sendMoneyBalanceRequest(), owns L$ balance +#include "llsurface.h" +#include "lltexturecache.h" +#include "lltexturefetch.h" +#include "lltoolmgr.h" +#include "lltrans.h" +#include "llui.h" +#include "llurldispatcher.h" +#include "llurlentry.h" +#include "llslurl.h" +#include "llurlhistory.h" +#include "llurlwhitelist.h" +#include "llvieweraudio.h" +#include "llviewerassetstorage.h" +#include "llviewercamera.h" +#include "llviewerdisplay.h" +#include "llviewergenericmessage.h" +#include "llviewergesture.h" +#include "llviewertexturelist.h" +#include "llviewermedia.h" +#include "llviewermenu.h" +#include "llviewermessage.h" +#include "llviewernetwork.h" +#include "llviewerobjectlist.h" +#include "llviewerparcelmedia.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" +#include "llviewerstats.h" +#include "llviewerthrottle.h" +#include "llviewerwindow.h" +#include "llvoavatar.h" +#include "llvoavatarself.h" +#include "llvoclouds.h" +#include "llweb.h" +#include "llworld.h" +#include "llworldmapmessage.h" +#include "llxfermanager.h" +#include "pipeline.h" +#include "llappviewer.h" +#include "llfasttimerview.h" +#include "llfloatermap.h" +#include "llweb.h" +#include "llvoiceclient.h" +#include "llnamelistctrl.h" +#include "llnamebox.h" +#include "llnameeditor.h" +#include "llpostprocess.h" +#include "llwlparammanager.h" +#include "llwaterparammanager.h" +#include "llagentlanguage.h" +#include "llwearable.h" +#include "llinventorybridge.h" +#include "llappearancemgr.h" +#include "llavatariconctrl.h" +#include "llvoicechannel.h" + +#include "lllogin.h" +#include "llevents.h" +#include "llstartuplistener.h" + +#if LL_WINDOWS +#include "lldxhardware.h" +#endif + +// +// exported globals +// +bool gAgentMovementCompleted = false; +S32 gMaxAgentGroups; + +std::string SCREEN_HOME_FILENAME = "screen_home.bmp"; +std::string SCREEN_LAST_FILENAME = "screen_last.bmp"; + +LLPointer<LLViewerTexture> gStartTexture; + +// +// Imported globals +// +extern S32 gStartImageWidth; +extern S32 gStartImageHeight; + +// +// local globals +// +static bool gGotUseCircuitCodeAck = false; +static std::string sInitialOutfit; +static std::string sInitialOutfitGender; // "male" or "female" +static boost::signals2::connection sWearablesLoadedCon; + +static bool gUseCircuitCallbackCalled = false; + +EStartupState LLStartUp::gStartupState = STATE_FIRST; +LLSLURL LLStartUp::sStartSLURL; + +static LLPointer<LLCredential> gUserCredential; +static std::string gDisplayName; +static BOOL gRememberPassword = TRUE; + +static U64 gFirstSimHandle = 0; +static LLHost gFirstSim; +static std::string gFirstSimSeedCap; +static LLVector3 gAgentStartLookAt(1.0f, 0.f, 0.f); +static std::string gAgentStartLocation = "safe"; +static bool mLoginStatePastUI = false; + + +boost::scoped_ptr<LLEventPump> LLStartUp::sStateWatcher(new LLEventStream("StartupState")); +boost::scoped_ptr<LLStartupListener> LLStartUp::sListener(new LLStartupListener()); + +// +// local function declaration +// + +void login_show(); +void login_callback(S32 option, void* userdata); +void show_first_run_dialog(); +bool first_run_dialog_callback(const LLSD& notification, const LLSD& response); +void set_startup_status(const F32 frac, const std::string& string, const std::string& msg); +bool login_alert_status(const LLSD& notification, const LLSD& response); +void login_packet_failed(void**, S32 result); +void use_circuit_callback(void**, S32 result); +void register_viewer_callbacks(LLMessageSystem* msg); +void asset_callback_nothing(LLVFS*, const LLUUID&, LLAssetType::EType, void*, S32); +bool callback_choose_gender(const LLSD& notification, const LLSD& response); +void init_start_screen(S32 location_id); +void release_start_screen(); +void reset_login(); +LLSD transform_cert_args(LLPointer<LLCertificate> cert); +void general_cert_done(const LLSD& notification, const LLSD& response); +void trust_cert_done(const LLSD& notification, const LLSD& response); +void apply_udp_blacklist(const std::string& csv); +bool process_login_success_response(); +void transition_back_to_login_panel(const std::string& emsg); + +void callback_cache_name(const LLUUID& id, const std::string& full_name, bool is_group) +{ + LLNameBox::refreshAll(id, full_name, is_group); + LLNameEditor::refreshAll(id, full_name, is_group); + + // TODO: Actually be intelligent about the refresh. + // For now, just brute force refresh the dialogs. + dialog_refresh_all(); +} + +// +// exported functionality +// + +// +// local classes +// + +namespace +{ + class LLNullHTTPSender : public LLHTTPSender + { + virtual void send(const LLHost& host, + const std::string& message, const LLSD& body, + LLHTTPClient::ResponderPtr response) const + { + LL_WARNS("AppInit") << " attemped to send " << message << " to " << host + << " with null sender" << LL_ENDL; + } + }; +} + +void update_texture_fetch() +{ + LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread + LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread + LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread + gTextureList.updateImages(0.10f); +} + +// Returns false to skip other idle processing. Should only return +// true when all initialization done. +bool idle_startup() +{ + LLMemType mt1(LLMemType::MTYPE_STARTUP); + + const F32 PRECACHING_DELAY = gSavedSettings.getF32("PrecachingDelay"); + static LLTimer timeout; + static S32 timeout_count = 0; + + static LLTimer login_time; + + // until this is encapsulated, this little hack for the + // auth/transform loop will do. + static F32 progress = 0.10f; + + static std::string auth_desc; + static std::string auth_message; + + static LLVector3 initial_sun_direction(1.f, 0.f, 0.f); + static LLVector3 agent_start_position_region(10.f, 10.f, 10.f); // default for when no space server + + // last location by default + static S32 agent_location_id = START_LOCATION_ID_LAST; + static S32 location_which = START_LOCATION_ID_LAST; + + static bool show_connect_box = true; + + //static bool stipend_since_login = false; + + // HACK: These are things from the main loop that usually aren't done + // until initialization is complete, but need to be done here for things + // to work. + gIdleCallbacks.callFunctions(); + gViewerWindow->updateUI(); + LLMortician::updateClass(); + + const std::string delims (" "); + std::string system; + int begIdx, endIdx; + std::string osString = LLAppViewer::instance()->getOSInfo().getOSStringSimple(); + + begIdx = osString.find_first_not_of (delims); + endIdx = osString.find_first_of (delims, begIdx); + system = osString.substr (begIdx, endIdx - begIdx); + system += "Locale"; + + LLStringUtil::setLocale (LLTrans::getString(system)); + + if (!gNoRender) + { + //note: Removing this line will cause incorrect button size in the login screen. -- bao. + gTextureList.updateImages(0.01f) ; + } + + if ( STATE_FIRST == LLStartUp::getStartupState() ) + { + gViewerWindow->showCursor(); + gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT); + + ///////////////////////////////////////////////// + // + // Initialize stuff that doesn't need data from simulators + // + + if (LLFeatureManager::getInstance()->isSafe()) + { + LLNotificationsUtil::add("DisplaySetToSafe"); + } + else if ((gSavedSettings.getS32("LastFeatureVersion") < LLFeatureManager::getInstance()->getVersion()) && + (gSavedSettings.getS32("LastFeatureVersion") != 0)) + { + LLNotificationsUtil::add("DisplaySetToRecommended"); + } + else if ((gSavedSettings.getS32("LastGPUClass") != LLFeatureManager::getInstance()->getGPUClass()) && + (gSavedSettings.getS32("LastGPUClass") != -1)) + { + LLNotificationsUtil::add("DisplaySetToRecommended"); + } + else if (!gViewerWindow->getInitAlert().empty()) + { + LLNotificationsUtil::add(gViewerWindow->getInitAlert()); + } + + gSavedSettings.setS32("LastFeatureVersion", LLFeatureManager::getInstance()->getVersion()); + gSavedSettings.setS32("LastGPUClass", LLFeatureManager::getInstance()->getGPUClass()); + + // load dynamic GPU/feature tables from website (S3) + LLFeatureManager::getInstance()->fetchHTTPTables(); + + std::string xml_file = LLUI::locateSkin("xui_version.xml"); + LLXMLNodePtr root; + bool xml_ok = false; + if (LLXMLNode::parseFile(xml_file, root, NULL)) + { + if( (root->hasName("xui_version") ) ) + { + std::string value = root->getValue(); + F32 version = 0.0f; + LLStringUtil::convertToF32(value, version); + if (version >= 1.0f) + { + xml_ok = true; + } + } + } + if (!xml_ok) + { + // If XML is bad, there's a good possibility that notifications.xml is ALSO bad. + // If that's so, then we'll get a fatal error on attempting to load it, + // which will display a nontranslatable error message that says so. + // Otherwise, we'll display a reasonable error message that IS translatable. + LLAppViewer::instance()->earlyExit("BadInstallation"); + } + // + // Statistics stuff + // + + // Load autopilot and stats stuff + gAgentPilot.load(gSavedSettings.getString("StatsPilotFile")); + + //gErrorStream.setTime(gSavedSettings.getBOOL("LogTimestamps")); + + // Load the throttle settings + gViewerThrottle.load(); + + if (ll_init_ares() == NULL || !gAres->isInitialized()) + { + std::string diagnostic = "Could not start address resolution system"; + LL_WARNS("AppInit") << diagnostic << LL_ENDL; + LLAppViewer::instance()->earlyExit("LoginFailedNoNetwork", LLSD().with("DIAGNOSTIC", diagnostic)); + } + + // + // Initialize messaging system + // + LL_DEBUGS("AppInit") << "Initializing messaging system..." << LL_ENDL; + + std::string message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message_template.msg"); + + LLFILE* found_template = NULL; + found_template = LLFile::fopen(message_template_path, "r"); /* Flawfinder: ignore */ + + #if LL_WINDOWS + // On the windows dev builds, unpackaged, the message_template.msg + // file will be located in: + // build-vc**/newview/<config>/app_settings + if (!found_template) + { + message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "message_template.msg"); + found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */ + } + #elif LL_DARWIN + // On Mac dev builds, message_template.msg lives in: + // indra/build-*/newview/<config>/Second Life/Contents/Resources/app_settings + if (!found_template) + { + message_template_path = + gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, + "../Resources/app_settings", + "message_template.msg"); + found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */ + } + #endif + + if (found_template) + { + fclose(found_template); + + U32 port = gSavedSettings.getU32("UserConnectionPort"); + + if ((NET_USE_OS_ASSIGNED_PORT == port) && // if nothing specified on command line (-port) + (gSavedSettings.getBOOL("ConnectionPortEnabled"))) + { + port = gSavedSettings.getU32("ConnectionPort"); + } + + LLHTTPSender::setDefaultSender(new LLNullHTTPSender()); + + // TODO parameterize + const F32 circuit_heartbeat_interval = 5; + const F32 circuit_timeout = 100; + + const LLUseCircuitCodeResponder* responder = NULL; + bool failure_is_fatal = true; + + if(!start_messaging_system( + message_template_path, + port, + LLVersionInfo::getMajor(), + LLVersionInfo::getMinor(), + LLVersionInfo::getPatch(), + FALSE, + std::string(), + responder, + failure_is_fatal, + circuit_heartbeat_interval, + circuit_timeout)) + { + std::string diagnostic = llformat(" Error: %d", gMessageSystem->getErrorCode()); + LL_WARNS("AppInit") << diagnostic << LL_ENDL; + LLAppViewer::instance()->earlyExit("LoginFailedNoNetwork", LLSD().with("DIAGNOSTIC", diagnostic)); + } + + #if LL_WINDOWS + // On the windows dev builds, unpackaged, the message.xml file will + // be located in indra/build-vc**/newview/<config>/app_settings. + std::string message_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message.xml"); + + if (!LLFile::isfile(message_path.c_str())) + { + LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "")); + } + else + { + LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); + } + #else + LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); + #endif + + } + else + { + LLAppViewer::instance()->earlyExit("MessageTemplateNotFound", LLSD().with("PATH", message_template_path)); + } + + if(gMessageSystem && gMessageSystem->isOK()) + { + // Initialize all of the callbacks in case of bad message + // system data + LLMessageSystem* msg = gMessageSystem; + msg->setExceptionFunc(MX_UNREGISTERED_MESSAGE, + invalid_message_callback, + NULL); + msg->setExceptionFunc(MX_PACKET_TOO_SHORT, + invalid_message_callback, + NULL); + + // running off end of a packet is now valid in the case + // when a reader has a newer message template than + // the sender + /*msg->setExceptionFunc(MX_RAN_OFF_END_OF_PACKET, + invalid_message_callback, + NULL);*/ + msg->setExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE, + invalid_message_callback, + NULL); + + if (gSavedSettings.getBOOL("LogMessages")) + { + LL_DEBUGS("AppInit") << "Message logging activated!" << LL_ENDL; + msg->startLogging(); + } + + // start the xfer system. by default, choke the downloads + // a lot... + const S32 VIEWER_MAX_XFER = 3; + start_xfer_manager(gVFS); + gXferManager->setMaxIncomingXfers(VIEWER_MAX_XFER); + F32 xfer_throttle_bps = gSavedSettings.getF32("XferThrottle"); + if (xfer_throttle_bps > 1.f) + { + gXferManager->setUseAckThrottling(TRUE); + gXferManager->setAckThrottleBPS(xfer_throttle_bps); + } + gAssetStorage = new LLViewerAssetStorage(msg, gXferManager, gVFS, gStaticVFS); + + + F32 dropPercent = gSavedSettings.getF32("PacketDropPercentage"); + msg->mPacketRing.setDropPercentage(dropPercent); + + F32 inBandwidth = gSavedSettings.getF32("InBandwidth"); + F32 outBandwidth = gSavedSettings.getF32("OutBandwidth"); + if (inBandwidth != 0.f) + { + LL_DEBUGS("AppInit") << "Setting packetring incoming bandwidth to " << inBandwidth << LL_ENDL; + msg->mPacketRing.setUseInThrottle(TRUE); + msg->mPacketRing.setInBandwidth(inBandwidth); + } + if (outBandwidth != 0.f) + { + LL_DEBUGS("AppInit") << "Setting packetring outgoing bandwidth to " << outBandwidth << LL_ENDL; + msg->mPacketRing.setUseOutThrottle(TRUE); + msg->mPacketRing.setOutBandwidth(outBandwidth); + } + } + + LL_INFOS("AppInit") << "Message System Initialized." << LL_ENDL; + + //------------------------------------------------- + // Init audio, which may be needed for prefs dialog + // or audio cues in connection UI. + //------------------------------------------------- + + if (FALSE == gSavedSettings.getBOOL("NoAudio")) + { + gAudiop = NULL; + +#ifdef LL_OPENAL + if (!gAudiop +#if !LL_WINDOWS + && NULL == getenv("LL_BAD_OPENAL_DRIVER") +#endif // !LL_WINDOWS + ) + { + gAudiop = (LLAudioEngine *) new LLAudioEngine_OpenAL(); + } +#endif + +#ifdef LL_FMOD + if (!gAudiop +#if !LL_WINDOWS + && NULL == getenv("LL_BAD_FMOD_DRIVER") +#endif // !LL_WINDOWS + ) + { + gAudiop = (LLAudioEngine *) new LLAudioEngine_FMOD(); + } +#endif + + if (gAudiop) + { +#if LL_WINDOWS + // FMOD on Windows needs the window handle to stop playing audio + // when window is minimized. JC + void* window_handle = (HWND)gViewerWindow->getPlatformWindow(); +#else + void* window_handle = NULL; +#endif + bool init = gAudiop->init(kAUDIO_NUM_SOURCES, window_handle); + if(init) + { + gAudiop->setMuted(TRUE); + } + else + { + LL_WARNS("AppInit") << "Unable to initialize audio engine" << LL_ENDL; + delete gAudiop; + gAudiop = NULL; + } + + if (gAudiop) + { + // if the audio engine hasn't set up its own preferred handler for streaming audio then set up the generic streaming audio implementation which uses media plugins + if (NULL == gAudiop->getStreamingAudioImpl()) + { + LL_INFOS("AppInit") << "Using media plugins to render streaming audio" << LL_ENDL; + gAudiop->setStreamingAudioImpl(new LLStreamingAudio_MediaPlugins()); + } + } + } + } + + LL_INFOS("AppInit") << "Audio Engine Initialized." << LL_ENDL; + + if (LLTimer::knownBadTimer()) + { + LL_WARNS("AppInit") << "Unreliable timers detected (may be bad PCI chipset)!!" << LL_ENDL; + } + + // + // Log on to system + // + if (gUserCredential.isNull()) + { + gUserCredential = gLoginHandler.initializeLoginInfo(); + } + if (gUserCredential.isNull()) + { + show_connect_box = TRUE; + } + else if (gSavedSettings.getBOOL("AutoLogin")) + { + gRememberPassword = TRUE; + gSavedSettings.setBOOL("RememberPassword", TRUE); + show_connect_box = false; + } + else + { + gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); + show_connect_box = TRUE; + } + // Go to the next startup state + LLStartUp::setStartupState( STATE_BROWSER_INIT ); + return FALSE; + } + + + if (STATE_BROWSER_INIT == LLStartUp::getStartupState()) + { + LL_DEBUGS("AppInit") << "STATE_BROWSER_INIT" << LL_ENDL; + std::string msg = LLTrans::getString("LoginInitializingBrowser"); + set_startup_status(0.03f, msg.c_str(), gAgent.mMOTD.c_str()); + display_startup(); + // LLViewerMedia::initBrowser(); + LLStartUp::setStartupState( STATE_LOGIN_SHOW ); + return FALSE; + } + + + if (STATE_LOGIN_SHOW == LLStartUp::getStartupState()) + { + LL_DEBUGS("AppInit") << "Initializing Window" << LL_ENDL; + + // if we've gone backwards in the login state machine, to this state where we show the UI + // AND the debug setting to exit in this case is true, then go ahead and bail quickly + if ( mLoginStatePastUI && gSavedSettings.getBOOL("QuitOnLoginActivated") ) + { + // no requirement for notification here - just exit + LLAppViewer::instance()->earlyExitNoNotify(); + } + + gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); + + timeout_count = 0; + + if (show_connect_box) + { + // Load all the name information out of the login view + // NOTE: Hits "Attempted getFields with no login view shown" warning, since we don't + // show the login view until login_show() is called below. + if (gUserCredential.isNull()) + { + gUserCredential = gLoginHandler.initializeLoginInfo(); + } + if (gNoRender) + { + LL_ERRS("AppInit") << "Need to autologin or use command line with norender!" << LL_ENDL; + } + // Make sure the process dialog doesn't hide things + gViewerWindow->setShowProgress(FALSE); + + initialize_edit_menu(); + + // Show the login dialog + login_show(); + // connect dialog is already shown, so fill in the names + if (gUserCredential.notNull()) + { + LLPanelLogin::setFields( gUserCredential, gRememberPassword); + } + LLPanelLogin::giveFocus(); + + LLStartUp::setStartupState( STATE_LOGIN_WAIT ); // Wait for user input + } + else + { + // skip directly to message template verification + LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); + } + + // *NOTE: This is where LLViewerParcelMgr::getInstance() used to get allocated before becoming LLViewerParcelMgr::getInstance(). + + // *NOTE: This is where gHUDManager used to bet allocated before becoming LLHUDManager::getInstance(). + + // *NOTE: This is where gMuteList used to get allocated before becoming LLMuteList::getInstance(). + + // Login screen needs menus for preferences, but we can enter + // this startup phase more than once. + if (gLoginMenuBarView == NULL) + { + init_menus(); + } + + gViewerWindow->setNormalControlsVisible( FALSE ); + gLoginMenuBarView->setVisible( TRUE ); + gLoginMenuBarView->setEnabled( TRUE ); + show_debug_menus(); + + // Hide the splash screen + LLSplashScreen::hide(); + + // Push our window frontmost + gViewerWindow->getWindow()->show(); + display_startup(); + + // DEV-16927. The following code removes errant keystrokes that happen while the window is being + // first made visible. +#ifdef _WIN32 + MSG msg; + while( PeekMessage( &msg, /*All hWnds owned by this thread */ NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) ); +#endif + timeout.reset(); + return FALSE; + } + + if (STATE_LOGIN_WAIT == LLStartUp::getStartupState()) + { + // when we get to this state, we've already been past the login UI + // (possiblely automatically) - flag this so we can test in the + // STATE_LOGIN_SHOW state if we've gone backwards + mLoginStatePastUI = true; + + // Don't do anything. Wait for the login view to call the login_callback, + // which will push us to the next state. + + // Sleep so we don't spin the CPU + ms_sleep(1); + return FALSE; + } + + if (STATE_LOGIN_CLEANUP == LLStartUp::getStartupState()) + { + //reset the values that could have come in from a slurl + // DEV-42215: Make sure they're not empty -- gUserCredential + // might already have been set from gSavedSettings, and it's too bad + // to overwrite valid values with empty strings. + + if (show_connect_box) + { + // TODO if not use viewer auth + // Load all the name information out of the login view + LLPanelLogin::getFields(gUserCredential, gRememberPassword); + // end TODO + + // HACK: Try to make not jump on login + gKeyboard->resetKeys(); + } + + // when we get to this state, we've already been past the login UI + // (possiblely automatically) - flag this so we can test in the + // STATE_LOGIN_SHOW state if we've gone backwards + mLoginStatePastUI = true; + + // save the credentials + std::string userid = "unknown"; + if(gUserCredential.notNull()) + { + userid = gUserCredential->userID(); + gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword); + } + gSavedSettings.setBOOL("RememberPassword", gRememberPassword); + LL_INFOS("AppInit") << "Attempting login as: " << userid << LL_ENDL; + gDebugInfo["LoginName"] = userid; + + // create necessary directories + // *FIX: these mkdir's should error check + gDirUtilp->setLindenUserDir(userid); + LLFile::mkdir(gDirUtilp->getLindenUserDir()); + + // Set PerAccountSettingsFile to the default value. + std::string per_account_settings_file = LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount"); + gSavedSettings.setString("PerAccountSettingsFile", + gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, + LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount"))); + + // Note: can't store warnings files per account because some come up before login + + // Overwrite default user settings with user settings + LLAppViewer::instance()->loadSettingsFromDirectory("Account"); + + // Need to set the LastLogoff time here if we don't have one. LastLogoff is used for "Recent Items" calculation + // and startup time is close enough if we don't have a real value. + if (gSavedPerAccountSettings.getU32("LastLogoff") == 0) + { + gSavedPerAccountSettings.setU32("LastLogoff", time_corrected()); + } + + //Default the path if one isn't set. + // *NOTE: unable to check variable differ from "InstantMessageLogPath" because it was + // provided in pre 2.0 viewer. See EXT-6661 + if (gSavedPerAccountSettings.getString("InstantMessageLogPath").empty()) + { + gDirUtilp->setChatLogsDir(gDirUtilp->getOSUserAppDir()); + gSavedPerAccountSettings.setString("InstantMessageLogPath", gDirUtilp->getChatLogsDir()); + } + else + { + gDirUtilp->setChatLogsDir(gSavedPerAccountSettings.getString("InstantMessageLogPath")); + } + gDirUtilp->setPerAccountChatLogsDir(userid); + + LLFile::mkdir(gDirUtilp->getChatLogsDir()); + LLFile::mkdir(gDirUtilp->getPerAccountChatLogsDir()); + + + //good a place as any to create user windlight directories + std::string user_windlight_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight", "")); + LLFile::mkdir(user_windlight_path_name.c_str()); + + std::string user_windlight_skies_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", "")); + LLFile::mkdir(user_windlight_skies_path_name.c_str()); + + std::string user_windlight_water_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/water", "")); + LLFile::mkdir(user_windlight_water_path_name.c_str()); + + std::string user_windlight_days_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/days", "")); + LLFile::mkdir(user_windlight_days_path_name.c_str()); + + + if (show_connect_box) + { + LLSLURL slurl; + LLPanelLogin::closePanel(); + } + + + // Load URL History File + LLURLHistory::loadFile("url_history.xml"); + // Load location history + LLLocationHistory::getInstance()->load(); + + // Load Avatars icons cache + LLAvatarIconIDCache::getInstance()->load(); + + // Load media plugin cookies + LLViewerMedia::loadCookieFile(); + + //------------------------------------------------- + // Handle startup progress screen + //------------------------------------------------- + + // on startup the user can request to go to their home, + // their last location, or some URL "-url //sim/x/y[/z]" + // All accounts have both a home and a last location, and we don't support + // more locations than that. Choose the appropriate one. JC + switch (LLStartUp::getStartSLURL().getType()) + { + case LLSLURL::LOCATION: + agent_location_id = START_LOCATION_ID_URL; + location_which = START_LOCATION_ID_LAST; + break; + case LLSLURL::LAST_LOCATION: + agent_location_id = START_LOCATION_ID_LAST; + location_which = START_LOCATION_ID_LAST; + break; + default: + agent_location_id = START_LOCATION_ID_HOME; + location_which = START_LOCATION_ID_HOME; + break; + } + + gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT); + + if (!gNoRender) + { + init_start_screen(agent_location_id); + } + + // Display the startup progress bar. + gViewerWindow->setShowProgress(TRUE); + gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Quit")); + + // Poke the VFS, which could potentially block for a while if + // Windows XP is acting up + set_startup_status(0.07f, LLTrans::getString("LoginVerifyingCache"), LLStringUtil::null); + display_startup(); + + gVFS->pokeFiles(); + + LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT ); + + return FALSE; + } + + if(STATE_LOGIN_AUTH_INIT == LLStartUp::getStartupState()) + { + gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridLabel(); + + // Update progress status and the display loop. + auth_desc = LLTrans::getString("LoginInProgress"); + set_startup_status(progress, auth_desc, auth_message); + progress += 0.02f; + display_startup(); + + // Setting initial values... + LLLoginInstance* login = LLLoginInstance::getInstance(); + login->setNotificationsInterface(LLNotifications::getInstance()); + if(gNoRender) + { + // HACK, skip optional updates if you're running drones + login->setSkipOptionalUpdate(true); + } + + login->setSerialNumber(LLAppViewer::instance()->getSerialNumber()); + login->setLastExecEvent(gLastExecEvent); + login->setUpdaterLauncher(boost::bind(&LLAppViewer::launchUpdater, LLAppViewer::instance())); + + // This call to LLLoginInstance::connect() starts the + // authentication process. + login->connect(gUserCredential); + + LLStartUp::setStartupState( STATE_LOGIN_CURL_UNSTUCK ); + return FALSE; + } + + if(STATE_LOGIN_CURL_UNSTUCK == LLStartUp::getStartupState()) + { + // If we get here we have gotten past the potential stall + // in curl, so take "may appear frozen" out of progress bar. JC + auth_desc = LLTrans::getString("LoginInProgressNoFrozen"); + set_startup_status(progress, auth_desc, auth_message); + + LLStartUp::setStartupState( STATE_LOGIN_PROCESS_RESPONSE ); + return FALSE; + } + + if(STATE_LOGIN_PROCESS_RESPONSE == LLStartUp::getStartupState()) + { + std::ostringstream emsg; + emsg << LLTrans::getString("LoginFailed") << "\n"; + if(LLLoginInstance::getInstance()->authFailure()) + { + LL_INFOS("LLStartup") << "Login failed, LLLoginInstance::getResponse(): " + << LLLoginInstance::getInstance()->getResponse() << LL_ENDL; + LLSD response = LLLoginInstance::getInstance()->getResponse(); + // Still have error conditions that may need some + // sort of handling. + std::string reason_response = response["reason"]; + std::string message_response = response["message"]; + + if(!message_response.empty()) + { + // XUI: fix translation for strings returned during login + // We need a generic table for translations + std::string big_reason = LLAgent::sTeleportErrorMessages[ message_response ]; + if ( big_reason.size() == 0 ) + { + emsg << message_response; + } + else + { + emsg << big_reason; + } + } + + if(reason_response == "key") + { + // Couldn't login because user/password is wrong + // Clear the credential + gUserCredential->clearAuthenticator(); + } + + if(reason_response == "update" + || reason_response == "optional") + { + // In the case of a needed update, quit. + // Its either downloading or declined. + // If optional was skipped this case shouldn't + // be reached. + LLLoginInstance::getInstance()->disconnect(); + LLAppViewer::instance()->forceQuit(); + } + else + { + if (reason_response != "tos") + { + // Don't pop up a notification in the TOS case because + // LLFloaterTOS::onCancel() already scolded the user. + std::string error_code; + if(response.has("errorcode")) + { + error_code = response["errorcode"].asString(); + } + if ((reason_response == "CURLError") && + (error_code == "SSL_CACERT" || error_code == "SSL_PEER_CERTIFICATE") && + response.has("certificate")) + { + // This was a certificate error, so grab the certificate + // and throw up the appropriate dialog. + LLPointer<LLCertificate> certificate = gSecAPIHandler->getCertificate(response["certificate"]); + if(certificate) + { + LLSD args = transform_cert_args(certificate); + + if(error_code == "SSL_CACERT") + { + // if we are handling an untrusted CA, throw up the dialog + // with the 'trust this CA' button. + LLNotificationsUtil::add("TrustCertificateError", args, response, + trust_cert_done); + + show_connect_box = true; + } + else + { + // the certificate exception returns a unique string for each type of exception. + // we grab this string via the LLUserAuth object, and use that to grab the localized + // string. + args["REASON"] = LLTrans::getString(message_response); + + LLNotificationsUtil::add("GeneralCertificateError", args, response, + general_cert_done); + + reset_login(); + gSavedSettings.setBOOL("AutoLogin", FALSE); + show_connect_box = true; + + } + + } + } + else + { + // This wasn't a certificate error, so throw up the normal + // notificatioin message. + LLSD args; + args["ERROR_MESSAGE"] = emsg.str(); + LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL; + LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done); + } + } + //setup map of datetime strings to codes and slt & local time offset from utc + // *TODO: Does this need to be here? + LLStringOps::setupDatetimeInfo (false); + transition_back_to_login_panel(emsg.str()); + show_connect_box = true; + } + } + else if(LLLoginInstance::getInstance()->authSuccess()) + { + if(process_login_success_response()) + { + // Pass the user information to the voice chat server interface. + LLVoiceClient::getInstance()->userAuthorized(gUserCredential->userID(), gAgentID); + // create the default proximal channel + LLVoiceChannel::initClass(); + LLGridManager::getInstance()->setFavorite(); + LLStartUp::setStartupState( STATE_WORLD_INIT); + } + else + { + LLSD args; + args["ERROR_MESSAGE"] = emsg.str(); + LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL; + LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done); + transition_back_to_login_panel(emsg.str()); + show_connect_box = true; + return FALSE; + } + } + return FALSE; + } + + //--------------------------------------------------------------------- + // World Init + //--------------------------------------------------------------------- + if (STATE_WORLD_INIT == LLStartUp::getStartupState()) + { + set_startup_status(0.30f, LLTrans::getString("LoginInitializingWorld"), gAgent.mMOTD); + display_startup(); + // We should have an agent id by this point. + llassert(!(gAgentID == LLUUID::null)); + + // Finish agent initialization. (Requires gSavedSettings, builds camera) + gAgent.init(); + gAgentCamera.init(); + set_underclothes_menu_options(); + + // Since we connected, save off the settings so the user doesn't have to + // type the name/password again if we crash. + gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); + LLUIColorTable::instance().saveUserSettings(); + + // + // Initialize classes w/graphics stuff. + // + gTextureList.doPrefetchImages(); + LLSurface::initClasses(); + + LLFace::initClass(); + + LLDrawable::initClass(); + + // init the shader managers + LLPostProcess::initClass(); + LLWLParamManager::initClass(); + LLWaterParamManager::initClass(); + + LLViewerObject::initVOClasses(); + + // Initialize all our tools. Must be done after saved settings loaded. + // NOTE: This also is where gToolMgr used to be instantiated before being turned into a singleton. + LLToolMgr::getInstance()->initTools(); + + // Pre-load floaters, like the world map, that are slow to spawn + // due to XML complexity. + gViewerWindow->initWorldUI(); + + display_startup(); + + // This is where we used to initialize gWorldp. Original comment said: + // World initialization must be done after above window init + + // User might have overridden far clip + LLWorld::getInstance()->setLandFarClip(gAgentCamera.mDrawDistance); + + // Before we create the first region, we need to set the agent's mOriginGlobal + // This is necessary because creating objects before this is set will result in a + // bad mPositionAgent cache. + + gAgent.initOriginGlobal(from_region_handle(gFirstSimHandle)); + + LLWorld::getInstance()->addRegion(gFirstSimHandle, gFirstSim); + + LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle); + LL_INFOS("AppInit") << "Adding initial simulator " << regionp->getOriginGlobal() << LL_ENDL; + + regionp->setSeedCapability(gFirstSimSeedCap); + LL_DEBUGS("AppInit") << "Waiting for seed grant ...." << LL_ENDL; + + // Set agent's initial region to be the one we just created. + gAgent.setRegion(regionp); + + // Set agent's initial position, which will be read by LLVOAvatar when the avatar + // object is created. I think this must be done after setting the region. JC + gAgent.setPositionAgent(agent_start_position_region); + + display_startup(); + LLStartUp::setStartupState( STATE_MULTIMEDIA_INIT ); + + return FALSE; + } + + + //--------------------------------------------------------------------- + // Load QuickTime/GStreamer and other multimedia engines, can be slow. + // Do it while we're waiting on the network for our seed capability. JC + //--------------------------------------------------------------------- + if (STATE_MULTIMEDIA_INIT == LLStartUp::getStartupState()) + { + LLStartUp::multimediaInit(); + LLStartUp::setStartupState( STATE_FONT_INIT ); + return FALSE; + } + + // Loading fonts takes several seconds + if (STATE_FONT_INIT == LLStartUp::getStartupState()) + { + LLStartUp::fontInit(); + LLStartUp::setStartupState( STATE_SEED_GRANTED_WAIT ); + return FALSE; + } + + //--------------------------------------------------------------------- + // Wait for Seed Cap Grant + //--------------------------------------------------------------------- + if(STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState()) + { + return FALSE; + } + + + //--------------------------------------------------------------------- + // Seed Capability Granted + // no newMessage calls should happen before this point + //--------------------------------------------------------------------- + if (STATE_SEED_CAP_GRANTED == LLStartUp::getStartupState()) + { + update_texture_fetch(); + + if ( gViewerWindow != NULL) + { // This isn't the first logon attempt, so show the UI + gViewerWindow->setNormalControlsVisible( TRUE ); + } + gLoginMenuBarView->setVisible( FALSE ); + gLoginMenuBarView->setEnabled( FALSE ); + + if (!gNoRender) + { + // direct logging to the debug console's line buffer + LLError::logToFixedBuffer(gDebugView->mDebugConsolep); + + // set initial visibility of debug console + gDebugView->mDebugConsolep->setVisible(gSavedSettings.getBOOL("ShowDebugConsole")); + } + + // + // Set message handlers + // + LL_INFOS("AppInit") << "Initializing communications..." << LL_ENDL; + + // register callbacks for messages. . . do this after initial handshake to make sure that we don't catch any unwanted + register_viewer_callbacks(gMessageSystem); + + // Debugging info parameters + gMessageSystem->setMaxMessageTime( 0.5f ); // Spam if decoding all msgs takes more than 500 ms + + #ifndef LL_RELEASE_FOR_DOWNLOAD + gMessageSystem->setTimeDecodes( TRUE ); // Time the decode of each msg + gMessageSystem->setTimeDecodesSpamThreshold( 0.05f ); // Spam if a single msg takes over 50ms to decode + #endif + + gXferManager->registerCallbacks(gMessageSystem); + + LLStartUp::initNameCache(); + + // update the voice settings *after* gCacheName initialization + // so that we can construct voice UI that relies on the name cache + LLVoiceClient::getInstance()->updateSettings(); + + //gCacheName is required for nearby chat history loading + //so I just moved nearby history loading a few states further + if (!gNoRender && gSavedPerAccountSettings.getBOOL("LogShowHistory")) + { + LLNearbyChat* nearby_chat = LLNearbyChat::getInstance(); + if (nearby_chat) nearby_chat->loadHistory(); + } + + // *Note: this is where gWorldMap used to be initialized. + + // register null callbacks for audio until the audio system is initialized + gMessageSystem->setHandlerFuncFast(_PREHASH_SoundTrigger, null_message_callback, NULL); + gMessageSystem->setHandlerFuncFast(_PREHASH_AttachedSound, null_message_callback, NULL); + + //reset statistics + LLViewerStats::getInstance()->resetStats(); + + display_startup(); + // + // Set up region and surface defaults + // + + + // Sets up the parameters for the first simulator + + LL_DEBUGS("AppInit") << "Initializing camera..." << LL_ENDL; + gFrameTime = totalTime(); + F32 last_time = gFrameTimeSeconds; + gFrameTimeSeconds = (S64)(gFrameTime - gStartTime)/SEC_TO_MICROSEC; + + gFrameIntervalSeconds = gFrameTimeSeconds - last_time; + if (gFrameIntervalSeconds < 0.f) + { + gFrameIntervalSeconds = 0.f; + } + + // Make sure agent knows correct aspect ratio + // FOV limits depend upon aspect ratio so this needs to happen before initializing the FOV below + LLViewerCamera::getInstance()->setViewHeightInPixels(gViewerWindow->getWorldViewHeightRaw()); + LLViewerCamera::getInstance()->setAspect(gViewerWindow->getWorldViewAspectRatio()); + // Initialize FOV + LLViewerCamera::getInstance()->setDefaultFOV(gSavedSettings.getF32("CameraAngle")); + + // Move agent to starting location. The position handed to us by + // the space server is in global coordinates, but the agent frame + // is in region local coordinates. Therefore, we need to adjust + // the coordinates handed to us to fit in the local region. + + gAgent.setPositionAgent(agent_start_position_region); + gAgent.resetAxes(gAgentStartLookAt); + gAgentCamera.stopCameraAnimation(); + gAgentCamera.resetCamera(); + + // Initialize global class data needed for surfaces (i.e. textures) + if (!gNoRender) + { + LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL; + // Initialize all of the viewer object classes for the first time (doing things like texture fetches. + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + + gSky.init(initial_sun_direction); + + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + } + + LL_DEBUGS("AppInit") << "Decoding images..." << LL_ENDL; + // For all images pre-loaded into viewer cache, decode them. + // Need to do this AFTER we init the sky + const S32 DECODE_TIME_SEC = 2; + for (int i = 0; i < DECODE_TIME_SEC; i++) + { + F32 frac = (F32)i / (F32)DECODE_TIME_SEC; + set_startup_status(0.45f + frac*0.1f, LLTrans::getString("LoginDecodingImages"), gAgent.mMOTD); + display_startup(); + gTextureList.decodeAllImages(1.f); + } + LLStartUp::setStartupState( STATE_WORLD_WAIT ); + + // JC - Do this as late as possible to increase likelihood Purify + // will run. + LLMessageSystem* msg = gMessageSystem; + if (!msg->mOurCircuitCode) + { + LL_WARNS("AppInit") << "Attempting to connect to simulator with a zero circuit code!" << LL_ENDL; + } + + gUseCircuitCallbackCalled = false; + + msg->enableCircuit(gFirstSim, TRUE); + // now, use the circuit info to tell simulator about us! + LL_INFOS("AppInit") << "viewer: UserLoginLocationReply() Enabling " << gFirstSim << " with code " << msg->mOurCircuitCode << LL_ENDL; + msg->newMessageFast(_PREHASH_UseCircuitCode); + msg->nextBlockFast(_PREHASH_CircuitCode); + msg->addU32Fast(_PREHASH_Code, msg->mOurCircuitCode); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_ID, gAgent.getID()); + msg->sendReliable( + gFirstSim, + gSavedSettings.getS32("UseCircuitCodeMaxRetries"), + FALSE, + gSavedSettings.getF32("UseCircuitCodeTimeout"), + use_circuit_callback, + NULL); + + timeout.reset(); + + return FALSE; + } + + //--------------------------------------------------------------------- + // Agent Send + //--------------------------------------------------------------------- + if(STATE_WORLD_WAIT == LLStartUp::getStartupState()) + { + LL_DEBUGS("AppInit") << "Waiting for simulator ack...." << LL_ENDL; + set_startup_status(0.59f, LLTrans::getString("LoginWaitingForRegionHandshake"), gAgent.mMOTD); + if(gGotUseCircuitCodeAck) + { + LLStartUp::setStartupState( STATE_AGENT_SEND ); + } + LLMessageSystem* msg = gMessageSystem; + while (msg->checkAllMessages(gFrameCount, gServicePump)) + { + } + msg->processAcks(); + return FALSE; + } + + //--------------------------------------------------------------------- + // Agent Send + //--------------------------------------------------------------------- + if (STATE_AGENT_SEND == LLStartUp::getStartupState()) + { + LL_DEBUGS("AppInit") << "Connecting to region..." << LL_ENDL; + set_startup_status(0.60f, LLTrans::getString("LoginConnectingToRegion"), gAgent.mMOTD); + // register with the message system so it knows we're + // expecting this message + LLMessageSystem* msg = gMessageSystem; + msg->setHandlerFuncFast( + _PREHASH_AgentMovementComplete, + process_agent_movement_complete); + LLViewerRegion* regionp = gAgent.getRegion(); + if(regionp) + { + send_complete_agent_movement(regionp->getHost()); + gAssetStorage->setUpstream(regionp->getHost()); + gCacheName->setUpstream(regionp->getHost()); + msg->newMessageFast(_PREHASH_EconomyDataRequest); + gAgent.sendReliableMessage(); + } + + // Create login effect + // But not on first login, because you can't see your avatar then + if (!gAgent.isFirstLogin()) + { + LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); + effectp->setPositionGlobal(gAgent.getPositionGlobal()); + effectp->setColor(LLColor4U(gAgent.getEffectColor())); + LLHUDManager::getInstance()->sendEffects(); + } + + LLStartUp::setStartupState( STATE_AGENT_WAIT ); // Go to STATE_AGENT_WAIT + + timeout.reset(); + return FALSE; + } + + //--------------------------------------------------------------------- + // Agent Wait + //--------------------------------------------------------------------- + if (STATE_AGENT_WAIT == LLStartUp::getStartupState()) + { + LLMessageSystem* msg = gMessageSystem; + while (msg->checkAllMessages(gFrameCount, gServicePump)) + { + if (gAgentMovementCompleted) + { + // Sometimes we have more than one message in the + // queue. break out of this loop and continue + // processing. If we don't, then this could skip one + // or more login steps. + break; + } + else + { + LL_DEBUGS("AppInit") << "Awaiting AvatarInitComplete, got " + << msg->getMessageName() << LL_ENDL; + } + } + msg->processAcks(); + + if (gAgentMovementCompleted) + { + LLStartUp::setStartupState( STATE_INVENTORY_SEND ); + } + + return FALSE; + } + + //--------------------------------------------------------------------- + // Inventory Send + //--------------------------------------------------------------------- + if (STATE_INVENTORY_SEND == LLStartUp::getStartupState()) + { + // Inform simulator of our language preference + LLAgentLanguage::update(); + + // unpack thin inventory + LLSD response = LLLoginInstance::getInstance()->getResponse(); + //bool dump_buffer = false; + + LLSD inv_lib_root = response["inventory-lib-root"]; + if(inv_lib_root.isDefined()) + { + // should only be one + LLSD id = inv_lib_root[0]["folder_id"]; + if(id.isDefined()) + { + gInventory.setLibraryRootFolderID(id.asUUID()); + } + } + + LLSD inv_lib_owner = response["inventory-lib-owner"]; + if(inv_lib_owner.isDefined()) + { + // should only be one + LLSD id = inv_lib_owner[0]["agent_id"]; + if(id.isDefined()) + { + gInventory.setLibraryOwnerID( LLUUID(id.asUUID())); + } + } + + LLSD inv_skel_lib = response["inventory-skel-lib"]; + if(inv_skel_lib.isDefined() && gInventory.getLibraryOwnerID().notNull()) + { + if(!gInventory.loadSkeleton(inv_skel_lib, gInventory.getLibraryOwnerID())) + { + LL_WARNS("AppInit") << "Problem loading inventory-skel-lib" << LL_ENDL; + } + } + + LLSD inv_skeleton = response["inventory-skeleton"]; + if(inv_skeleton.isDefined()) + { + if(!gInventory.loadSkeleton(inv_skeleton, gAgent.getID())) + { + LL_WARNS("AppInit") << "Problem loading inventory-skel-targets" << LL_ENDL; + } + } + + LLSD buddy_list = response["buddy-list"]; + if(buddy_list.isDefined()) + { + LLAvatarTracker::buddy_map_t list; + LLUUID agent_id; + S32 has_rights = 0, given_rights = 0; + for(LLSD::array_const_iterator it = buddy_list.beginArray(), + end = buddy_list.endArray(); it != end; ++it) + { + LLSD buddy_id = (*it)["buddy_id"]; + if(buddy_id.isDefined()) + { + agent_id = buddy_id.asUUID(); + } + + LLSD buddy_rights_has = (*it)["buddy_rights_has"]; + if(buddy_rights_has.isDefined()) + { + has_rights = buddy_rights_has.asInteger(); + } + + LLSD buddy_rights_given = (*it)["buddy_rights_given"]; + if(buddy_rights_given.isDefined()) + { + given_rights = buddy_rights_given.asInteger(); + } + + list[agent_id] = new LLRelationship(given_rights, has_rights, false); + } + LLAvatarTracker::instance().addBuddyList(list); + } + + bool show_hud = false; + LLSD tutorial_setting = response["tutorial_setting"]; + if(tutorial_setting.isDefined()) + { + for(LLSD::array_const_iterator it = tutorial_setting.beginArray(), + end = tutorial_setting.endArray(); it != end; ++it) + { + LLSD tutorial_url = (*it)["tutorial_url"]; + if(tutorial_url.isDefined()) + { + // Tutorial floater will append language code + gSavedSettings.setString("TutorialURL", tutorial_url.asString()); + } + + // For Viewer 2.0 we are not using the web-based tutorial + // If we reverse that decision, put this code back and use + // login.cgi to send a different URL with content that matches + // the Viewer 2.0 UI. + //LLSD use_tutorial = (*it)["use_tutorial"]; + //if(use_tutorial.asString() == "true") + //{ + // show_hud = true; + //} + } + } + // Either we want to show tutorial because this is the first login + // to a Linden Help Island or the user quit with the tutorial + // visible. JC + if (show_hud || gSavedSettings.getBOOL("ShowTutorial")) + { + LLFloaterReg::showInstance("hud", LLSD(), FALSE); + } + + LLSD event_notifications = response["event_notifications"]; + if(event_notifications.isDefined()) + { + gEventNotifier.load(event_notifications); + } + + LLSD classified_categories = response["classified_categories"]; + if(classified_categories.isDefined()) + { + LLClassifiedInfo::loadCategories(classified_categories); + } + + // This method MUST be called before gInventory.findCategoryUUIDForType because of + // gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap. + gInventory.buildParentChildMap(); + + //all categories loaded. lets create "My Favorites" category + gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE,true); + + // set up callbacks + llinfos << "Registering Callbacks" << llendl; + LLMessageSystem* msg = gMessageSystem; + llinfos << " Inventory" << llendl; + LLInventoryModel::registerCallbacks(msg); + llinfos << " AvatarTracker" << llendl; + LLAvatarTracker::instance().registerCallbacks(msg); + llinfos << " Landmark" << llendl; + LLLandmark::registerCallbacks(msg); + + // request mute list + llinfos << "Requesting Mute List" << llendl; + LLMuteList::getInstance()->requestFromServer(gAgent.getID()); + + // Get L$ and ownership credit information + llinfos << "Requesting Money Balance" << llendl; + LLStatusBar::sendMoneyBalanceRequest(); + + // request all group information + llinfos << "Requesting Agent Data" << llendl; + gAgent.sendAgentDataUpdateRequest(); + + // Create the inventory views + llinfos << "Creating Inventory Views" << llendl; + LLFloaterReg::getInstance("inventory"); + + LLStartUp::setStartupState( STATE_MISC ); + return FALSE; + } + + + //--------------------------------------------------------------------- + // Misc + //--------------------------------------------------------------------- + if (STATE_MISC == LLStartUp::getStartupState()) + { + // We have a region, and just did a big inventory download. + // We can estimate the user's connection speed, and set their + // max bandwidth accordingly. JC + if (gSavedSettings.getBOOL("FirstLoginThisInstall")) + { + // This is actually a pessimistic computation, because TCP may not have enough + // time to ramp up on the (small) default inventory file to truly measure max + // bandwidth. JC + F64 rate_bps = LLLoginInstance::getInstance()->getLastTransferRateBPS(); + const F32 FAST_RATE_BPS = 600.f * 1024.f; + const F32 FASTER_RATE_BPS = 750.f * 1024.f; + F32 max_bandwidth = gViewerThrottle.getMaxBandwidth(); + if (rate_bps > FASTER_RATE_BPS + && rate_bps > max_bandwidth) + { + LL_DEBUGS("AppInit") << "Fast network connection, increasing max bandwidth to " + << FASTER_RATE_BPS/1024.f + << " kbps" << LL_ENDL; + gViewerThrottle.setMaxBandwidth(FASTER_RATE_BPS / 1024.f); + } + else if (rate_bps > FAST_RATE_BPS + && rate_bps > max_bandwidth) + { + LL_DEBUGS("AppInit") << "Fast network connection, increasing max bandwidth to " + << FAST_RATE_BPS/1024.f + << " kbps" << LL_ENDL; + gViewerThrottle.setMaxBandwidth(FAST_RATE_BPS / 1024.f); + } + + // Set the show start location to true, now that the user has logged + // on with this install. + gSavedSettings.setBOOL("ShowStartLocation", TRUE); + } + + // We're successfully logged in. + gSavedSettings.setBOOL("FirstLoginThisInstall", FALSE); + + LLFloaterReg::showInitialVisibleInstances(); + + // based on the comments, we've successfully logged in so we can delete the 'forced' + // URL that the updater set in settings.ini (in a mostly paranoid fashion) + std::string nextLoginLocation = gSavedSettings.getString( "NextLoginLocation" ); + if ( nextLoginLocation.length() ) + { + // clear it + gSavedSettings.setString( "NextLoginLocation", "" ); + + // and make sure it's saved + gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile") , TRUE ); + LLUIColorTable::instance().saveUserSettings(); + }; + + if (!gNoRender) + { + // JC: Initializing audio requests many sounds for download. + init_audio(); + + // JC: Initialize "active" gestures. This may also trigger + // many gesture downloads, if this is the user's first + // time on this machine or -purge has been run. + LLSD gesture_options + = LLLoginInstance::getInstance()->getResponse("gestures"); + if (gesture_options.isDefined()) + { + LL_DEBUGS("AppInit") << "Gesture Manager loading " << gesture_options.size() + << LL_ENDL; + uuid_vec_t item_ids; + for(LLSD::array_const_iterator resp_it = gesture_options.beginArray(), + end = gesture_options.endArray(); resp_it != end; ++resp_it) + { + // If the id is not specifed in the LLSD, + // the LLSD operator[]() will return a null LLUUID. + LLUUID item_id = (*resp_it)["item_id"]; + LLUUID asset_id = (*resp_it)["asset_id"]; + + if (item_id.notNull() && asset_id.notNull()) + { + // Could schedule and delay these for later. + const BOOL no_inform_server = FALSE; + const BOOL no_deactivate_similar = FALSE; + LLGestureMgr::instance().activateGestureWithAsset(item_id, asset_id, + no_inform_server, + no_deactivate_similar); + // We need to fetch the inventory items for these gestures + // so we have the names to populate the UI. + item_ids.push_back(item_id); + } + } + // no need to add gesture to inventory observer, it's already made in constructor + LLGestureMgr::instance().setFetchIDs(item_ids); + LLGestureMgr::instance().startFetch(); + } + } + gDisplaySwapBuffers = TRUE; + + LLMessageSystem* msg = gMessageSystem; + msg->setHandlerFuncFast(_PREHASH_SoundTrigger, process_sound_trigger); + msg->setHandlerFuncFast(_PREHASH_PreloadSound, process_preload_sound); + msg->setHandlerFuncFast(_PREHASH_AttachedSound, process_attached_sound); + msg->setHandlerFuncFast(_PREHASH_AttachedSoundGainChange, process_attached_sound_gain_change); + + LL_DEBUGS("AppInit") << "Initialization complete" << LL_ENDL; + + gRenderStartTime.reset(); + gForegroundTime.reset(); + + // HACK: Inform simulator of window size. + // Do this here so it's less likely to race with RegisterNewAgent. + // TODO: Put this into RegisterNewAgent + // JC - 7/20/2002 + gViewerWindow->sendShapeToSim(); + + + // Ignore stipend information for now. Money history is on the web site. + // if needed, show the L$ history window + //if (stipend_since_login && !gNoRender) + //{ + //} + + // The reason we show the alert is because we want to + // reduce confusion for when you log in and your provided + // location is not your expected location. So, if this is + // your first login, then you do not have an expectation, + // thus, do not show this alert. + if (!gAgent.isFirstLogin()) + { + llinfos << "gAgentStartLocation : " << gAgentStartLocation << llendl; + LLSLURL start_slurl = LLStartUp::getStartSLURL(); + + if (((start_slurl.getType() == LLSLURL::LOCATION) && (gAgentStartLocation == "url")) || + ((start_slurl.getType() == LLSLURL::LAST_LOCATION) && (gAgentStartLocation == "last")) || + ((start_slurl.getType() == LLSLURL::HOME_LOCATION) && (gAgentStartLocation == "home"))) + { + // Start location is OK + // Disabled code to restore camera location and focus if logging in to default location + static bool samename = false; + if (samename) + { + // restore old camera pos + gAgentCamera.setFocusOnAvatar(FALSE, FALSE); + gAgentCamera.setCameraPosAndFocusGlobal(gSavedSettings.getVector3d("CameraPosOnLogout"), gSavedSettings.getVector3d("FocusPosOnLogout"), LLUUID::null); + BOOL limit_hit = FALSE; + gAgentCamera.calcCameraPositionTargetGlobal(&limit_hit); + if (limit_hit) + { + gAgentCamera.setFocusOnAvatar(TRUE, FALSE); + } + gAgentCamera.stopCameraAnimation(); + } + } + else + { + std::string msg; + switch(start_slurl.getType()) + { + case LLSLURL::LOCATION: + { + + msg = "AvatarMovedDesired"; + break; + } + case LLSLURL::HOME_LOCATION: + { + msg = "AvatarMovedHome"; + break; + } + default: + { + msg = "AvatarMovedLast"; + } + } + LLNotificationsUtil::add(msg); + } + } + + //DEV-17797. get null folder. Any items found here moved to Lost and Found + LLInventoryModelBackgroundFetch::instance().findLostItems(); + + LLStartUp::setStartupState( STATE_PRECACHE ); + timeout.reset(); + return FALSE; + } + + if (STATE_PRECACHE == LLStartUp::getStartupState()) + { + F32 timeout_frac = timeout.getElapsedTimeF32()/PRECACHING_DELAY; + + // We now have an inventory skeleton, so if this is a user's first + // login, we can start setting up their clothing and avatar + // appearance. This helps to avoid the generic "Ruth" avatar in + // the orientation island tutorial experience. JC + if (gAgent.isFirstLogin() + && !sInitialOutfit.empty() // registration set up an outfit + && !sInitialOutfitGender.empty() // and a gender + && isAgentAvatarValid() // can't wear clothes without object + && !gAgent.isGenderChosen() ) // nothing already loading + { + // Start loading the wearables, textures, gestures + LLStartUp::loadInitialOutfit( sInitialOutfit, sInitialOutfitGender ); + } + + // wait precache-delay and for agent's avatar or a lot longer. + if(((timeout_frac > 1.f) && isAgentAvatarValid()) + || (timeout_frac > 3.f)) + { + LLStartUp::setStartupState( STATE_WEARABLES_WAIT ); + } + else + { + update_texture_fetch(); + set_startup_status(0.60f + 0.30f * timeout_frac, + LLTrans::getString("LoginPrecaching"), + gAgent.mMOTD); + display_startup(); + if (!LLViewerShaderMgr::sInitialized) + { + LLViewerShaderMgr::sInitialized = TRUE; + LLViewerShaderMgr::instance()->setShaders(); + } + } + + return TRUE; + } + + if (STATE_WEARABLES_WAIT == LLStartUp::getStartupState()) + { + static LLFrameTimer wearables_timer; + + const F32 wearables_time = wearables_timer.getElapsedTimeF32(); + const F32 MAX_WEARABLES_TIME = 10.f; + + if (!gAgent.isGenderChosen()) + { + // No point in waiting for clothing, we don't even + // know what gender we are. Pop a dialog to ask and + // proceed to draw the world. JC + // + // *NOTE: We might hit this case even if we have an + // initial outfit, but if the load hasn't started + // already then something is wrong so fall back + // to generic outfits. JC + LLNotificationsUtil::add("WelcomeChooseSex", LLSD(), LLSD(), + callback_choose_gender); + LLStartUp::setStartupState( STATE_CLEANUP ); + return TRUE; + } + + if (wearables_time > MAX_WEARABLES_TIME) + { + LLNotificationsUtil::add("ClothingLoading"); + LLViewerStats::getInstance()->incStat(LLViewerStats::ST_WEARABLES_TOO_LONG); + LLStartUp::setStartupState( STATE_CLEANUP ); + return TRUE; + } + + if (gAgent.isFirstLogin()) + { + // wait for avatar to be completely loaded + if (isAgentAvatarValid() + && gAgentAvatarp->isFullyLoaded()) + { + //llinfos << "avatar fully loaded" << llendl; + LLStartUp::setStartupState( STATE_CLEANUP ); + return TRUE; + } + } + else + { + // OK to just get the wearables + if ( gAgentWearables.areWearablesLoaded() ) + { + // We have our clothing, proceed. + //llinfos << "wearables loaded" << llendl; + LLStartUp::setStartupState( STATE_CLEANUP ); + return TRUE; + } + } + + update_texture_fetch(); + set_startup_status(0.9f + 0.1f * wearables_time / MAX_WEARABLES_TIME, + LLTrans::getString("LoginDownloadingClothing").c_str(), + gAgent.mMOTD.c_str()); + return TRUE; + } + + if (STATE_CLEANUP == LLStartUp::getStartupState()) + { + set_startup_status(1.0, "", ""); + + // Let the map know about the inventory. + LLFloaterWorldMap* floater_world_map = LLFloaterWorldMap::getInstance(); + if(floater_world_map) + { + floater_world_map->observeInventory(&gInventory); + floater_world_map->observeFriends(); + } + gViewerWindow->showCursor(); + gViewerWindow->getWindow()->resetBusyCount(); + gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); + LL_DEBUGS("AppInit") << "Done releasing bitmap" << LL_ENDL; + gViewerWindow->setShowProgress(FALSE); + gViewerWindow->setProgressCancelButtonVisible(FALSE); + + // We're not away from keyboard, even though login might have taken + // a while. JC + gAgent.clearAFK(); + + // Have the agent start watching the friends list so we can update proxies + gAgent.observeFriends(); + if (gSavedSettings.getBOOL("LoginAsGod")) + { + gAgent.requestEnterGodMode(); + } + + // Start automatic replay if the flag is set. + if (gSavedSettings.getBOOL("StatsAutoRun") || LLAgentPilot::sReplaySession) + { + LLUUID id; + LL_DEBUGS("AppInit") << "Starting automatic playback" << LL_ENDL; + gAgentPilot.startPlayback(); + } + + show_debug_menus(); // Debug menu visiblity and First Use trigger + + // If we've got a startup URL, dispatch it + LLStartUp::dispatchURL(); + + // Retrieve information about the land data + // (just accessing this the first time will fetch it, + // then the data is cached for the viewer's lifetime) + LLProductInfoRequestManager::instance(); + + // *FIX:Mani - What do I do here? + // Need we really clear the Auth response data? + // Clean up the userauth stuff. + // LLUserAuth::getInstance()->reset(); + + LLStartUp::setStartupState( STATE_STARTED ); + + // Unmute audio if desired and setup volumes. + // Unmute audio if desired and setup volumes. + // This is a not-uncommon crash site, so surround it with + // llinfos output to aid diagnosis. + LL_INFOS("AppInit") << "Doing first audio_update_volume..." << LL_ENDL; + audio_update_volume(); + LL_INFOS("AppInit") << "Done first audio_update_volume." << LL_ENDL; + + // reset keyboard focus to sane state of pointing at world + gFocusMgr.setKeyboardFocus(NULL); + +#if 0 // sjb: enable for auto-enabling timer display + gDebugView->mFastTimerView->setVisible(TRUE); +#endif + + LLAppViewer::instance()->handleLoginComplete(); + + // reset timers now that we are running "logged in" logic + LLFastTimer::reset(); + + LLAgentPicksInfo::getInstance()->requestNumberOfPicks(); + + LLIMFloater::initIMFloater(); + + return TRUE; + } + + LL_WARNS("AppInit") << "Reached end of idle_startup for state " << LLStartUp::getStartupState() << LL_ENDL; + return TRUE; +} + +// +// local function definition +// + +void login_show() +{ + LL_INFOS("AppInit") << "Initializing Login Screen" << LL_ENDL; + +#ifdef LL_RELEASE_FOR_DOWNLOAD + BOOL bUseDebugLogin = gSavedSettings.getBOOL("UseDebugLogin"); +#else + BOOL bUseDebugLogin = TRUE; +#endif + + LLPanelLogin::show( gViewerWindow->getWindowRectScaled(), + bUseDebugLogin || gSavedSettings.getBOOL("SecondLifeEnterprise"), + login_callback, NULL ); + +} + +// Callback for when login screen is closed. Option 0 = connect, option 1 = quit. +void login_callback(S32 option, void *userdata) +{ + const S32 CONNECT_OPTION = 0; + const S32 QUIT_OPTION = 1; + + if (CONNECT_OPTION == option) + { + LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); + return; + } + else if (QUIT_OPTION == option) // *TODO: THIS CODE SEEMS TO BE UNREACHABLE!!!!! login_callback is never called with option equal to QUIT_OPTION + { + if (!gSavedSettings.getBOOL("RememberPassword")) + { + // turn off the setting and write out to disk + gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile") , TRUE ); + LLUIColorTable::instance().saveUserSettings(); + } + + // Next iteration through main loop should shut down the app cleanly. + LLAppViewer::instance()->userQuit(); + + if (LLAppViewer::instance()->quitRequested()) + { + LLPanelLogin::closePanel(); + } + return; + } + else + { + LL_WARNS("AppInit") << "Unknown login button clicked" << LL_ENDL; + } +} + +void show_first_run_dialog() +{ + LLNotificationsUtil::add("FirstRun", LLSD(), LLSD(), first_run_dialog_callback); +} + +bool first_run_dialog_callback(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (0 == option) + { + LL_DEBUGS("AppInit") << "First run dialog cancelling" << LL_ENDL; + LLWeb::loadURLExternal(LLTrans::getString("create_account_url") ); + } + + LLPanelLogin::giveFocus(); + return false; +} + + + +void set_startup_status(const F32 frac, const std::string& string, const std::string& msg) +{ + gViewerWindow->setProgressPercent(frac*100); + gViewerWindow->setProgressString(string); + + gViewerWindow->setProgressMessage(msg); +} + +bool login_alert_status(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + // Buttons + switch( option ) + { + case 0: // OK + break; + // case 1: // Help + // LLWeb::loadURL(LLNotifications::instance().getGlobalString("SUPPORT_URL") ); + // break; + case 2: // Teleport + // Restart the login process, starting at our home locaton + LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME)); + LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); + break; + default: + LL_WARNS("AppInit") << "Missing case in login_alert_status switch" << LL_ENDL; + } + + LLPanelLogin::giveFocus(); + return false; +} + + +void use_circuit_callback(void**, S32 result) +{ + // bail if we're quitting. + if(LLApp::isExiting()) return; + if( !gUseCircuitCallbackCalled ) + { + gUseCircuitCallbackCalled = true; + if (result) + { + // Make sure user knows something bad happened. JC + LL_WARNS("AppInit") << "Backing up to login screen!" << LL_ENDL; + LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status); + reset_login(); + } + else + { + gGotUseCircuitCodeAck = true; + } + } +} + +void register_viewer_callbacks(LLMessageSystem* msg) +{ + msg->setHandlerFuncFast(_PREHASH_LayerData, process_layer_data ); + msg->setHandlerFuncFast(_PREHASH_ImageData, LLViewerTextureList::receiveImageHeader ); + msg->setHandlerFuncFast(_PREHASH_ImagePacket, LLViewerTextureList::receiveImagePacket ); + msg->setHandlerFuncFast(_PREHASH_ObjectUpdate, process_object_update ); + msg->setHandlerFunc("ObjectUpdateCompressed", process_compressed_object_update ); + msg->setHandlerFunc("ObjectUpdateCached", process_cached_object_update ); + msg->setHandlerFuncFast(_PREHASH_ImprovedTerseObjectUpdate, process_terse_object_update_improved ); + msg->setHandlerFunc("SimStats", process_sim_stats); + msg->setHandlerFuncFast(_PREHASH_HealthMessage, process_health_message ); + msg->setHandlerFuncFast(_PREHASH_EconomyData, process_economy_data); + msg->setHandlerFunc("RegionInfo", LLViewerRegion::processRegionInfo); + + msg->setHandlerFuncFast(_PREHASH_ChatFromSimulator, process_chat_from_simulator); + msg->setHandlerFuncFast(_PREHASH_KillObject, process_kill_object, NULL); + msg->setHandlerFuncFast(_PREHASH_SimulatorViewerTimeMessage, process_time_synch, NULL); + msg->setHandlerFuncFast(_PREHASH_EnableSimulator, process_enable_simulator); + msg->setHandlerFuncFast(_PREHASH_DisableSimulator, process_disable_simulator); + msg->setHandlerFuncFast(_PREHASH_KickUser, process_kick_user, NULL); + + msg->setHandlerFunc("CrossedRegion", process_crossed_region); + msg->setHandlerFuncFast(_PREHASH_TeleportFinish, process_teleport_finish); + + msg->setHandlerFuncFast(_PREHASH_AlertMessage, process_alert_message); + msg->setHandlerFunc("AgentAlertMessage", process_agent_alert_message); + msg->setHandlerFuncFast(_PREHASH_MeanCollisionAlert, process_mean_collision_alert_message, NULL); + msg->setHandlerFunc("ViewerFrozenMessage", process_frozen_message); + + msg->setHandlerFuncFast(_PREHASH_NameValuePair, process_name_value); + msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair, process_remove_name_value); + msg->setHandlerFuncFast(_PREHASH_AvatarAnimation, process_avatar_animation); + msg->setHandlerFuncFast(_PREHASH_AvatarAppearance, process_avatar_appearance); + msg->setHandlerFunc("AgentCachedTextureResponse", LLAgent::processAgentCachedTextureResponse); + msg->setHandlerFunc("RebakeAvatarTextures", LLVOAvatarSelf::processRebakeAvatarTextures); + msg->setHandlerFuncFast(_PREHASH_CameraConstraint, process_camera_constraint); + msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse, process_avatar_sit_response); + msg->setHandlerFunc("SetFollowCamProperties", process_set_follow_cam_properties); + msg->setHandlerFunc("ClearFollowCamProperties", process_clear_follow_cam_properties); + + msg->setHandlerFuncFast(_PREHASH_ImprovedInstantMessage, process_improved_im); + msg->setHandlerFuncFast(_PREHASH_ScriptQuestion, process_script_question); + msg->setHandlerFuncFast(_PREHASH_ObjectProperties, LLSelectMgr::processObjectProperties, NULL); + msg->setHandlerFuncFast(_PREHASH_ObjectPropertiesFamily, LLSelectMgr::processObjectPropertiesFamily, NULL); + msg->setHandlerFunc("ForceObjectSelect", LLSelectMgr::processForceObjectSelect); + + msg->setHandlerFuncFast(_PREHASH_MoneyBalanceReply, process_money_balance_reply, NULL); + msg->setHandlerFuncFast(_PREHASH_CoarseLocationUpdate, LLWorld::processCoarseUpdate, NULL); + msg->setHandlerFuncFast(_PREHASH_ReplyTaskInventory, LLViewerObject::processTaskInv, NULL); + msg->setHandlerFuncFast(_PREHASH_DerezContainer, process_derez_container, NULL); + msg->setHandlerFuncFast(_PREHASH_ScriptRunningReply, + &LLLiveLSLEditor::processScriptRunningReply); + + msg->setHandlerFuncFast(_PREHASH_DeRezAck, process_derez_ack); + + msg->setHandlerFunc("LogoutReply", process_logout_reply); + + //msg->setHandlerFuncFast(_PREHASH_AddModifyAbility, + // &LLAgent::processAddModifyAbility); + //msg->setHandlerFuncFast(_PREHASH_RemoveModifyAbility, + // &LLAgent::processRemoveModifyAbility); + msg->setHandlerFuncFast(_PREHASH_AgentDataUpdate, + &LLAgent::processAgentDataUpdate); + msg->setHandlerFuncFast(_PREHASH_AgentGroupDataUpdate, + &LLAgent::processAgentGroupDataUpdate); + msg->setHandlerFunc("AgentDropGroup", + &LLAgent::processAgentDropGroup); + // land ownership messages + msg->setHandlerFuncFast(_PREHASH_ParcelOverlay, + LLViewerParcelMgr::processParcelOverlay); + msg->setHandlerFuncFast(_PREHASH_ParcelProperties, + LLViewerParcelMgr::processParcelProperties); + msg->setHandlerFunc("ParcelAccessListReply", + LLViewerParcelMgr::processParcelAccessListReply); + msg->setHandlerFunc("ParcelDwellReply", + LLViewerParcelMgr::processParcelDwellReply); + + msg->setHandlerFunc("AvatarPropertiesReply", + &LLAvatarPropertiesProcessor::processAvatarPropertiesReply); + msg->setHandlerFunc("AvatarInterestsReply", + &LLAvatarPropertiesProcessor::processAvatarInterestsReply); + msg->setHandlerFunc("AvatarGroupsReply", + &LLAvatarPropertiesProcessor::processAvatarGroupsReply); + // ratings deprecated + //msg->setHandlerFuncFast(_PREHASH_AvatarStatisticsReply, + // LLPanelAvatar::processAvatarStatisticsReply); + msg->setHandlerFunc("AvatarNotesReply", + &LLAvatarPropertiesProcessor::processAvatarNotesReply); + msg->setHandlerFunc("AvatarPicksReply", + &LLAvatarPropertiesProcessor::processAvatarPicksReply); + msg->setHandlerFunc("AvatarClassifiedReply", + &LLAvatarPropertiesProcessor::processAvatarClassifiedsReply); + + msg->setHandlerFuncFast(_PREHASH_CreateGroupReply, + LLGroupMgr::processCreateGroupReply); + msg->setHandlerFuncFast(_PREHASH_JoinGroupReply, + LLGroupMgr::processJoinGroupReply); + msg->setHandlerFuncFast(_PREHASH_EjectGroupMemberReply, + LLGroupMgr::processEjectGroupMemberReply); + msg->setHandlerFuncFast(_PREHASH_LeaveGroupReply, + LLGroupMgr::processLeaveGroupReply); + msg->setHandlerFuncFast(_PREHASH_GroupProfileReply, + LLGroupMgr::processGroupPropertiesReply); + + // ratings deprecated + // msg->setHandlerFuncFast(_PREHASH_ReputationIndividualReply, + // LLFloaterRate::processReputationIndividualReply); + + msg->setHandlerFuncFast(_PREHASH_AgentWearablesUpdate, + LLAgentWearables::processAgentInitialWearablesUpdate ); + + msg->setHandlerFunc("ScriptControlChange", + LLAgent::processScriptControlChange ); + + msg->setHandlerFuncFast(_PREHASH_ViewerEffect, LLHUDManager::processViewerEffect); + + msg->setHandlerFuncFast(_PREHASH_GrantGodlikePowers, process_grant_godlike_powers); + + msg->setHandlerFuncFast(_PREHASH_GroupAccountSummaryReply, + LLPanelGroupLandMoney::processGroupAccountSummaryReply); + msg->setHandlerFuncFast(_PREHASH_GroupAccountDetailsReply, + LLPanelGroupLandMoney::processGroupAccountDetailsReply); + msg->setHandlerFuncFast(_PREHASH_GroupAccountTransactionsReply, + LLPanelGroupLandMoney::processGroupAccountTransactionsReply); + + msg->setHandlerFuncFast(_PREHASH_UserInfoReply, + process_user_info_reply); + + msg->setHandlerFunc("RegionHandshake", process_region_handshake, NULL); + + msg->setHandlerFunc("TeleportStart", process_teleport_start ); + msg->setHandlerFunc("TeleportProgress", process_teleport_progress); + msg->setHandlerFunc("TeleportFailed", process_teleport_failed, NULL); + msg->setHandlerFunc("TeleportLocal", process_teleport_local, NULL); + + msg->setHandlerFunc("ImageNotInDatabase", LLViewerTextureList::processImageNotInDatabase, NULL); + + msg->setHandlerFuncFast(_PREHASH_GroupMembersReply, + LLGroupMgr::processGroupMembersReply); + msg->setHandlerFunc("GroupRoleDataReply", + LLGroupMgr::processGroupRoleDataReply); + msg->setHandlerFunc("GroupRoleMembersReply", + LLGroupMgr::processGroupRoleMembersReply); + msg->setHandlerFunc("GroupTitlesReply", + LLGroupMgr::processGroupTitlesReply); + // Special handler as this message is sometimes used for group land. + msg->setHandlerFunc("PlacesReply", process_places_reply); + msg->setHandlerFunc("GroupNoticesListReply", LLPanelGroupNotices::processGroupNoticesListReply); + + msg->setHandlerFunc("AvatarPickerReply", LLFloaterAvatarPicker::processAvatarPickerReply); + + msg->setHandlerFunc("MapBlockReply", LLWorldMapMessage::processMapBlockReply); + msg->setHandlerFunc("MapItemReply", LLWorldMapMessage::processMapItemReply); + msg->setHandlerFunc("EventInfoReply", LLEventNotifier::processEventInfoReply); + + msg->setHandlerFunc("PickInfoReply", &LLAvatarPropertiesProcessor::processPickInfoReply); +// msg->setHandlerFunc("ClassifiedInfoReply", LLPanelClassified::processClassifiedInfoReply); + msg->setHandlerFunc("ClassifiedInfoReply", LLAvatarPropertiesProcessor::processClassifiedInfoReply); + msg->setHandlerFunc("ParcelInfoReply", LLRemoteParcelInfoProcessor::processParcelInfoReply); + msg->setHandlerFunc("ScriptDialog", process_script_dialog); + msg->setHandlerFunc("LoadURL", process_load_url); + msg->setHandlerFunc("ScriptTeleportRequest", process_script_teleport_request); + msg->setHandlerFunc("EstateCovenantReply", process_covenant_reply); + + // calling cards + msg->setHandlerFunc("OfferCallingCard", process_offer_callingcard); + msg->setHandlerFunc("AcceptCallingCard", process_accept_callingcard); + msg->setHandlerFunc("DeclineCallingCard", process_decline_callingcard); + + msg->setHandlerFunc("ParcelObjectOwnersReply", LLPanelLandObjects::processParcelObjectOwnersReply); + + msg->setHandlerFunc("InitiateDownload", process_initiate_download); + msg->setHandlerFunc("LandStatReply", LLFloaterTopObjects::handle_land_reply); + msg->setHandlerFunc("GenericMessage", process_generic_message); + + msg->setHandlerFuncFast(_PREHASH_FeatureDisabled, process_feature_disabled_message); +} + +void asset_callback_nothing(LLVFS*, const LLUUID&, LLAssetType::EType, void*, S32) +{ + // nothing +} + +// *HACK: Must match name in Library or agent inventory +const std::string ROOT_GESTURES_FOLDER = "Gestures"; +const std::string COMMON_GESTURES_FOLDER = "Common Gestures"; +const std::string MALE_GESTURES_FOLDER = "Male Gestures"; +const std::string FEMALE_GESTURES_FOLDER = "Female Gestures"; +const std::string SPEECH_GESTURES_FOLDER = "Speech Gestures"; +const std::string OTHER_GESTURES_FOLDER = "Other Gestures"; +const S32 OPT_CLOSED_WINDOW = -1; +const S32 OPT_MALE = 0; +const S32 OPT_FEMALE = 1; +const S32 OPT_TRUST_CERT = 0; +const S32 OPT_CANCEL_TRUST = 1; + +bool callback_choose_gender(const LLSD& notification, const LLSD& response) +{ + + // These defaults are returned from the server on login. They are set in login.xml. + // If no default is returned from the server, they are retrieved from settings.xml. + + S32 option = LLNotification::getSelectedOption(notification, response); + switch(option) + { + case OPT_MALE: + LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultMaleAvatar"), "male" ); + break; + + case OPT_FEMALE: + case OPT_CLOSED_WINDOW: + default: + LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultFemaleAvatar"), "female" ); + break; + } + return false; +} + +void LLStartUp::copyLibraryGestures(const std::string& same_gender_gestures) +{ + llinfos << "Copying library gestures" << llendl; + + // Copy gestures + LLUUID lib_gesture_cat_id = + gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE,false,true); + if (lib_gesture_cat_id.isNull()) + { + llwarns << "Unable to copy gestures, source category not found" << llendl; + } + LLUUID dst_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE); + + std::vector<std::string> gesture_folders_to_copy; + gesture_folders_to_copy.push_back(MALE_GESTURES_FOLDER); + gesture_folders_to_copy.push_back(FEMALE_GESTURES_FOLDER); + gesture_folders_to_copy.push_back(COMMON_GESTURES_FOLDER); + gesture_folders_to_copy.push_back(SPEECH_GESTURES_FOLDER); + gesture_folders_to_copy.push_back(OTHER_GESTURES_FOLDER); + + for(std::vector<std::string>::iterator it = gesture_folders_to_copy.begin(); + it != gesture_folders_to_copy.end(); + ++it) + { + std::string& folder_name = *it; + + LLPointer<LLInventoryCallback> cb(NULL); + + if (folder_name == same_gender_gestures || + folder_name == COMMON_GESTURES_FOLDER || + folder_name == OTHER_GESTURES_FOLDER) + { + cb = new ActivateGestureCallback; + } + + + LLUUID cat_id = findDescendentCategoryIDByName(lib_gesture_cat_id,folder_name); + if (cat_id.isNull()) + { + llwarns << "failed to find gesture folder for " << folder_name << llendl; + } + else + { + llinfos << "initiating fetch and copy for " << folder_name << " cat_id " << cat_id << llendl; + LLAppearanceMgr* app_mgr = LLAppearanceMgr::getInstance(); + callAfterCategoryFetch(cat_id, + boost::bind(&LLAppearanceMgr::shallowCopyCategory, + app_mgr, + cat_id, + dst_id, + cb)); + } + } +} + +void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, + const std::string& gender_name ) +{ + llinfos << "starting" << llendl; + + // Not going through the processAgentInitialWearables path, so need to set this here. + LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); + // Initiate creation of COF, since we're also bypassing that. + gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); + + S32 gender = 0; + std::string same_gender_gestures; + if (gender_name == "male") + { + gender = OPT_MALE; + same_gender_gestures = MALE_GESTURES_FOLDER; + } + else + { + gender = OPT_FEMALE; + same_gender_gestures = FEMALE_GESTURES_FOLDER; + } + + // try to find the outfit - if not there, create some default + // wearables. + LLUUID cat_id = findDescendentCategoryIDByName( + gInventory.getLibraryRootFolderID(), + outfit_folder_name); + if (cat_id.isNull()) + { + gAgentWearables.createStandardWearables(gender); + } + else + { + sWearablesLoadedCon = gAgentWearables.addLoadedCallback(LLStartUp::saveInitialOutfit); + + bool do_copy = true; + bool do_append = false; + LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id); + LLAppearanceMgr::instance().wearInventoryCategory(cat, do_copy, do_append); + } + + // Copy gestures + copyLibraryGestures(same_gender_gestures); + + // This is really misnamed -- it means we have started loading + // an outfit/shape that will give the avatar a gender eventually. JC + gAgent.setGenderChosen(TRUE); + +} + +//static +void LLStartUp::saveInitialOutfit() +{ + if (sInitialOutfit.empty()) return; + + if (sWearablesLoadedCon.connected()) + { + sWearablesLoadedCon.disconnect(); + } + LLAppearanceMgr::getInstance()->makeNewOutfitLinks(sInitialOutfit,false); +} + +std::string& LLStartUp::getInitialOutfitName() +{ + return sInitialOutfit; +} + +// Loads a bitmap to display during load +void init_start_screen(S32 location_id) +{ + if (gStartTexture.notNull()) + { + gStartTexture = NULL; + LL_INFOS("AppInit") << "re-initializing start screen" << LL_ENDL; + } + + LL_DEBUGS("AppInit") << "Loading startup bitmap..." << LL_ENDL; + + std::string temp_str = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter(); + + if ((S32)START_LOCATION_ID_LAST == location_id) + { + temp_str += SCREEN_LAST_FILENAME; + } + else + { + temp_str += SCREEN_HOME_FILENAME; + } + + LLPointer<LLImageBMP> start_image_bmp = new LLImageBMP; + + // Turn off start screen to get around the occasional readback + // driver bug + if(!gSavedSettings.getBOOL("UseStartScreen")) + { + LL_INFOS("AppInit") << "Bitmap load disabled" << LL_ENDL; + return; + } + else if(!start_image_bmp->load(temp_str) ) + { + LL_WARNS("AppInit") << "Bitmap load failed" << LL_ENDL; + return; + } + + gStartImageWidth = start_image_bmp->getWidth(); + gStartImageHeight = start_image_bmp->getHeight(); + + LLPointer<LLImageRaw> raw = new LLImageRaw; + if (!start_image_bmp->decode(raw, 0.0f)) + { + LL_WARNS("AppInit") << "Bitmap decode failed" << LL_ENDL; + gStartTexture = NULL; + return; + } + + raw->expandToPowerOfTwo(); + gStartTexture = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE) ; +} + + +// frees the bitmap +void release_start_screen() +{ + LL_DEBUGS("AppInit") << "Releasing bitmap..." << LL_ENDL; + gStartTexture = NULL; +} + + +// static +std::string LLStartUp::startupStateToString(EStartupState state) +{ +#define RTNENUM(E) case E: return #E + switch(state){ + RTNENUM( STATE_FIRST ); + RTNENUM( STATE_BROWSER_INIT ); + RTNENUM( STATE_LOGIN_SHOW ); + RTNENUM( STATE_LOGIN_WAIT ); + RTNENUM( STATE_LOGIN_CLEANUP ); + RTNENUM( STATE_LOGIN_AUTH_INIT ); + RTNENUM( STATE_LOGIN_CURL_UNSTUCK ); + RTNENUM( STATE_LOGIN_PROCESS_RESPONSE ); + RTNENUM( STATE_WORLD_INIT ); + RTNENUM( STATE_MULTIMEDIA_INIT ); + RTNENUM( STATE_FONT_INIT ); + RTNENUM( STATE_SEED_GRANTED_WAIT ); + RTNENUM( STATE_SEED_CAP_GRANTED ); + RTNENUM( STATE_WORLD_WAIT ); + RTNENUM( STATE_AGENT_SEND ); + RTNENUM( STATE_AGENT_WAIT ); + RTNENUM( STATE_INVENTORY_SEND ); + RTNENUM( STATE_MISC ); + RTNENUM( STATE_PRECACHE ); + RTNENUM( STATE_WEARABLES_WAIT ); + RTNENUM( STATE_CLEANUP ); + RTNENUM( STATE_STARTED ); + default: + return llformat("(state #%d)", state); + } +#undef RTNENUM +} + +// static +void LLStartUp::setStartupState( EStartupState state ) +{ + LL_INFOS("AppInit") << "Startup state changing from " << + getStartupStateString() << " to " << + startupStateToString(state) << LL_ENDL; + gStartupState = state; + postStartupState(); +} + +void LLStartUp::postStartupState() +{ + LLSD stateInfo; + stateInfo["str"] = getStartupStateString(); + stateInfo["enum"] = gStartupState; + sStateWatcher->post(stateInfo); +} + + +void reset_login() +{ + gAgentWearables.cleanup(); + gAgentCamera.cleanup(); + gAgent.cleanup(); + LLWorld::getInstance()->destroyClass(); + + LLStartUp::setStartupState( STATE_LOGIN_SHOW ); + + if ( gViewerWindow ) + { // Hide menus and normal buttons + gViewerWindow->setNormalControlsVisible( FALSE ); + gLoginMenuBarView->setVisible( TRUE ); + gLoginMenuBarView->setEnabled( TRUE ); + } + + // Hide any other stuff + LLFloaterReg::hideVisibleInstances(); +} + +//--------------------------------------------------------------------------- + +// Initialize all plug-ins except the web browser (which was initialized +// early, before the login screen). JC +void LLStartUp::multimediaInit() +{ + LL_DEBUGS("AppInit") << "Initializing Multimedia...." << LL_ENDL; + std::string msg = LLTrans::getString("LoginInitializingMultimedia"); + set_startup_status(0.42f, msg.c_str(), gAgent.mMOTD.c_str()); + display_startup(); + + // LLViewerMedia::initClass(); + LLViewerParcelMedia::initClass(); +} + +void LLStartUp::fontInit() +{ + LL_DEBUGS("AppInit") << "Initializing fonts...." << LL_ENDL; + std::string msg = LLTrans::getString("LoginInitializingFonts"); + set_startup_status(0.45f, msg.c_str(), gAgent.mMOTD.c_str()); + display_startup(); + + LLFontGL::loadDefaultFonts(); +} + +void LLStartUp::initNameCache() +{ + // Can be called multiple times + if ( gCacheName ) return; + + gCacheName = new LLCacheName(gMessageSystem); + gCacheName->addObserver(&callback_cache_name); + gCacheName->localizeCacheName("waiting", LLTrans::getString("AvatarNameWaiting")); + gCacheName->localizeCacheName("nobody", LLTrans::getString("AvatarNameNobody")); + gCacheName->localizeCacheName("none", LLTrans::getString("GroupNameNone")); + // Load stored cache if possible + LLAppViewer::instance()->loadNameCache(); + + // Start cache in not-running state until we figure out if we have + // capabilities for display name lookup + LLAvatarNameCache::initClass(false); + LLAvatarNameCache::setUseDisplayNames(gSavedSettings.getBOOL("UseDisplayNames")); +} + +void LLStartUp::cleanupNameCache() +{ + LLAvatarNameCache::cleanupClass(); + + delete gCacheName; + gCacheName = NULL; +} + +bool LLStartUp::dispatchURL() +{ + // ok, if we've gotten this far and have a startup URL + if (!getStartSLURL().isValid()) + { + return false; + } + if(getStartSLURL().getType() != LLSLURL::APP) + { + + // If we started with a location, but we're already + // at that location, don't pop dialogs open. + LLVector3 pos = gAgent.getPositionAgent(); + LLVector3 slurlpos = getStartSLURL().getPosition(); + F32 dx = pos.mV[VX] - slurlpos.mV[VX]; + F32 dy = pos.mV[VY] - slurlpos.mV[VY]; + const F32 SLOP = 2.f; // meters + + if( getStartSLURL().getRegion() != gAgent.getRegion()->getName() + || (dx*dx > SLOP*SLOP) + || (dy*dy > SLOP*SLOP) ) + { + LLURLDispatcher::dispatch(getStartSLURL().getSLURLString(), + NULL, false); + } + return true; + } + return false; +} + +void LLStartUp::setStartSLURL(const LLSLURL& slurl) +{ + sStartSLURL = slurl; + switch(slurl.getType()) + { + case LLSLURL::HOME_LOCATION: + { + gSavedSettings.setString("LoginLocation", LLSLURL::SIM_LOCATION_HOME); + break; + } + case LLSLURL::LAST_LOCATION: + { + gSavedSettings.setString("LoginLocation", LLSLURL::SIM_LOCATION_LAST); + break; + } + default: + LLGridManager::getInstance()->setGridChoice(slurl.getGrid()); + break; + } +} + +bool login_alert_done(const LLSD& notification, const LLSD& response) +{ + LLPanelLogin::giveFocus(); + return false; +} + +// parse the certificate information into args for the +// certificate notifications +LLSD transform_cert_args(LLPointer<LLCertificate> cert) +{ + LLSD args = LLSD::emptyMap(); + std::string value; + LLSD cert_info; + cert->getLLSD(cert_info); + // convert all of the elements in the cert into + // args for the xml dialog, so we have flexability to + // display various parts of the cert by only modifying + // the cert alert dialog xml. + for(LLSD::map_iterator iter = cert_info.beginMap(); + iter != cert_info.endMap(); + iter++) + { + // key usage and extended key usage + // are actually arrays, and we want to format them as comma separated + // strings, so special case those. + LLSDSerialize::toXML(cert_info[iter->first], std::cout); + if((iter->first== std::string(CERT_KEY_USAGE)) | + (iter->first == std::string(CERT_EXTENDED_KEY_USAGE))) + { + value = ""; + LLSD usage = cert_info[iter->first]; + for (LLSD::array_iterator usage_iter = usage.beginArray(); + usage_iter != usage.endArray(); + usage_iter++) + { + + if(usage_iter != usage.beginArray()) + { + value += ", "; + } + + value += (*usage_iter).asString(); + } + + } + else + { + value = iter->second.asString(); + } + + std::string name = iter->first; + std::transform(name.begin(), name.end(), name.begin(), + (int(*)(int))toupper); + args[name.c_str()] = value; + } + return args; +} + + +// when we handle a cert error, give focus back to the login panel +void general_cert_done(const LLSD& notification, const LLSD& response) +{ + LLStartUp::setStartupState( STATE_LOGIN_SHOW ); + LLPanelLogin::giveFocus(); +} + +// check to see if the user wants to trust the cert. +// if they do, add it to the cert store and +void trust_cert_done(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + switch(option) + { + case OPT_TRUST_CERT: + { + LLPointer<LLCertificate> cert = gSecAPIHandler->getCertificate(notification["payload"]["certificate"]); + LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore(gSavedSettings.getString("CertStore")); + store->add(cert); + store->save(); + LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); + break; + } + case OPT_CANCEL_TRUST: + reset_login(); + gSavedSettings.setBOOL("AutoLogin", FALSE); + LLStartUp::setStartupState( STATE_LOGIN_SHOW ); + default: + LLPanelLogin::giveFocus(); + break; + } + +} + +void apply_udp_blacklist(const std::string& csv) +{ + + std::string::size_type start = 0; + std::string::size_type comma = 0; + do + { + comma = csv.find(",", start); + if (comma == std::string::npos) + { + comma = csv.length(); + } + std::string item(csv, start, comma-start); + + lldebugs << "udp_blacklist " << item << llendl; + gMessageSystem->banUdpMessage(item); + + start = comma + 1; + + } + while(comma < csv.length()); + +} + +bool process_login_success_response() +{ + LLSD response = LLLoginInstance::getInstance()->getResponse(); + + std::string text(response["udp_blacklist"]); + if(!text.empty()) + { + apply_udp_blacklist(text); + } + + // unpack login data needed by the application + text = response["agent_id"].asString(); + if(!text.empty()) gAgentID.set(text); + gDebugInfo["AgentID"] = text; + + // Agent id needed for parcel info request in LLUrlEntryParcel + // to resolve parcel name. + LLUrlEntryParcel::setAgentID(gAgentID); + + text = response["session_id"].asString(); + if(!text.empty()) gAgentSessionID.set(text); + gDebugInfo["SessionID"] = text; + + // Session id needed for parcel info request in LLUrlEntryParcel + // to resolve parcel name. + LLUrlEntryParcel::setSessionID(gAgentSessionID); + + text = response["secure_session_id"].asString(); + if(!text.empty()) gAgent.mSecureSessionID.set(text); + + // if the response contains a display name, use that, + // otherwise if the response contains a first and/or last name, + // use those. Otherwise use the credential identifier + + gDisplayName = ""; + if (response.has("display_name")) + { + gDisplayName.assign(response["display_name"].asString()); + if(!gDisplayName.empty()) + { + // Remove quotes from string. Login.cgi sends these to force + // names that look like numbers into strings. + LLStringUtil::replaceChar(gDisplayName, '"', ' '); + LLStringUtil::trim(gDisplayName); + } + } + if(gDisplayName.empty()) + { + if(response.has("first_name")) + { + gDisplayName.assign(response["first_name"].asString()); + LLStringUtil::replaceChar(gDisplayName, '"', ' '); + LLStringUtil::trim(gDisplayName); + } + if(response.has("last_name")) + { + text.assign(response["last_name"].asString()); + LLStringUtil::replaceChar(text, '"', ' '); + LLStringUtil::trim(text); + if(!gDisplayName.empty()) + { + gDisplayName += " "; + } + gDisplayName += text; + } + } + if(gDisplayName.empty()) + { + gDisplayName.assign(gUserCredential->asString()); + } + + // this is their actual ability to access content + text = response["agent_access_max"].asString(); + if (!text.empty()) + { + // agent_access can be 'A', 'M', and 'PG'. + gAgent.setMaturity(text[0]); + } + + // this is the value of their preference setting for that content + // which will always be <= agent_access_max + text = response["agent_region_access"].asString(); + if (!text.empty()) + { + U32 preferredMaturity = (U32)LLAgent::convertTextToMaturity(text[0]); + + gSavedSettings.setU32("PreferredMaturity", preferredMaturity); + } + // During the AO transition, this flag will be true. Then the flag will + // go away. After the AO transition, this code and all the code that + // uses it can be deleted. + text = response["ao_transition"].asString(); + if (!text.empty()) + { + if (text == "1") + { + gAgent.setAOTransition(); + } + } + + text = response["start_location"].asString(); + if(!text.empty()) + { + gAgentStartLocation.assign(text); + } + + text = response["circuit_code"].asString(); + if(!text.empty()) + { + gMessageSystem->mOurCircuitCode = strtoul(text.c_str(), NULL, 10); + } + std::string sim_ip_str = response["sim_ip"]; + std::string sim_port_str = response["sim_port"]; + if(!sim_ip_str.empty() && !sim_port_str.empty()) + { + U32 sim_port = strtoul(sim_port_str.c_str(), NULL, 10); + gFirstSim.set(sim_ip_str, sim_port); + if (gFirstSim.isOk()) + { + gMessageSystem->enableCircuit(gFirstSim, TRUE); + } + } + std::string region_x_str = response["region_x"]; + std::string region_y_str = response["region_y"]; + if(!region_x_str.empty() && !region_y_str.empty()) + { + U32 region_x = strtoul(region_x_str.c_str(), NULL, 10); + U32 region_y = strtoul(region_y_str.c_str(), NULL, 10); + gFirstSimHandle = to_region_handle(region_x, region_y); + } + + const std::string look_at_str = response["look_at"]; + if (!look_at_str.empty()) + { + size_t len = look_at_str.size(); + LLMemoryStream mstr((U8*)look_at_str.c_str(), len); + LLSD sd = LLSDSerialize::fromNotation(mstr, len); + gAgentStartLookAt = ll_vector3_from_sd(sd); + } + + text = response["seed_capability"].asString(); + if (!text.empty()) gFirstSimSeedCap = text; + + text = response["seconds_since_epoch"].asString(); + if(!text.empty()) + { + U32 server_utc_time = strtoul(text.c_str(), NULL, 10); + if(server_utc_time) + { + time_t now = time(NULL); + gUTCOffset = (server_utc_time - now); + } + } + + // this is the base used to construct help URLs + text = response["help_url_format"].asString(); + if (!text.empty()) + { + // replace the default help URL format + gSavedSettings.setString("HelpURLFormat",text); + + // don't fall back to Standalone's pre-connection static help + gSavedSettings.setBOOL("HelpUseLocal", false); + } + + std::string home_location = response["home"]; + if(!home_location.empty()) + { + size_t len = home_location.size(); + LLMemoryStream mstr((U8*)home_location.c_str(), len); + LLSD sd = LLSDSerialize::fromNotation(mstr, len); + S32 region_x = sd["region_handle"][0].asInteger(); + S32 region_y = sd["region_handle"][1].asInteger(); + U64 region_handle = to_region_handle(region_x, region_y); + LLVector3 position = ll_vector3_from_sd(sd["position"]); + gAgent.setHomePosRegion(region_handle, position); + } + + gAgent.mMOTD.assign(response["message"]); + + // Options... + // Each 'option' is an array of submaps. + // It appears that we only ever use the first element of the array. + LLUUID inv_root_folder_id = response["inventory-root"][0]["folder_id"]; + if(inv_root_folder_id.notNull()) + { + gInventory.setRootFolderID(inv_root_folder_id); + //gInventory.mock(gAgent.getInventoryRootID()); + } + + LLSD login_flags = response["login-flags"][0]; + if(login_flags.size()) + { + std::string flag = login_flags["ever_logged_in"]; + if(!flag.empty()) + { + gAgent.setFirstLogin((flag == "N") ? TRUE : FALSE); + } + + /* Flag is currently ignored by the viewer. + flag = login_flags["stipend_since_login"]; + if(flag == "Y") + { + stipend_since_login = true; + } + */ + + flag = login_flags["gendered"].asString(); + if(flag == "Y") + { + gAgent.setGenderChosen(TRUE); + } + + bool pacific_daylight_time = false; + flag = login_flags["daylight_savings"].asString(); + if(flag == "Y") + { + pacific_daylight_time = (flag == "Y"); + } + + //setup map of datetime strings to codes and slt & local time offset from utc + LLStringOps::setupDatetimeInfo(pacific_daylight_time); + } + + // set up the voice configuration. Ultimately, we should pass this up as part of each voice + // channel if we need to move to multiple voice servers per grid. + LLSD voice_config_info = response["voice-config"]; + if(voice_config_info.has("VoiceServerType")) + { + gSavedSettings.setString("VoiceServerType", voice_config_info["VoiceServerType"].asString()); + } + + // Request the map server url + std::string map_server_url = response["map-server-url"]; + if(!map_server_url.empty()) + { + // We got an answer from the grid -> use that for map for the current session + gSavedSettings.setString("CurrentMapServerURL", map_server_url); + LL_INFOS("LLStartup") << "map-server-url : we got an answer from the grid : " << map_server_url << LL_ENDL; + } + else + { + // No answer from the grid -> use the default setting for current session + map_server_url = gSavedSettings.getString("MapServerURL"); + gSavedSettings.setString("CurrentMapServerURL", map_server_url); + LL_INFOS("LLStartup") << "map-server-url : no map-server-url answer, we use the default setting for the map : " << map_server_url << LL_ENDL; + } + + // Default male and female avatars allowing the user to choose their avatar on first login. + // These may be passed up by SLE to allow choice of enterprise avatars instead of the standard + // "new ruth." Not to be confused with 'initial-outfit' below + LLSD newuser_config = response["newuser-config"][0]; + if(newuser_config.has("DefaultFemaleAvatar")) + { + gSavedSettings.setString("DefaultFemaleAvatar", newuser_config["DefaultFemaleAvatar"].asString()); + } + if(newuser_config.has("DefaultMaleAvatar")) + { + gSavedSettings.setString("DefaultMaleAvatar", newuser_config["DefaultMaleAvatar"].asString()); + } + + // Initial outfit for the user. + // QUESTION: Why can't we simply simply set the users outfit directly + // from a web page into the user info on the server? - Roxie + LLSD initial_outfit = response["initial-outfit"][0]; + if(initial_outfit.size()) + { + std::string flag = initial_outfit["folder_name"]; + if(!flag.empty()) + { + // Initial outfit is a folder in your inventory, + // must be an exact folder-name match. + sInitialOutfit = flag; + } + + flag = initial_outfit["gender"].asString(); + if(!flag.empty()) + { + sInitialOutfitGender = flag; + } + } + + LLSD global_textures = response["global-textures"][0]; + if(global_textures.size()) + { + // Extract sun and moon texture IDs. These are used + // in the LLVOSky constructor, but I can't figure out + // how to pass them in. JC + LLUUID id = global_textures["sun_texture_id"]; + if(id.notNull()) + { + gSunTextureID = id; + } + + id = global_textures["moon_texture_id"]; + if(id.notNull()) + { + gMoonTextureID = id; + } + + id = global_textures["cloud_texture_id"]; + if(id.notNull()) + { + gCloudTextureID = id; + } + } + + // Set the location of the snapshot sharing config endpoint + std::string snapshot_config_url = response["snapshot_config_url"]; + if(!snapshot_config_url.empty()) + { + gSavedSettings.setString("SnapshotConfigURL", snapshot_config_url); + } + + // Start the process of fetching the OpenID session cookie for this user login + std::string openid_url = response["openid_url"]; + if(!openid_url.empty()) + { + std::string openid_token = response["openid_token"]; + LLViewerMedia::openIDSetup(openid_url, openid_token); + } + + if(response.has("max-agent-groups")) { + std::string max_agent_groups(response["max-agent-groups"]); + gMaxAgentGroups = atoi(max_agent_groups.c_str()); + LL_INFOS("LLStartup") << "gMaxAgentGroups read from login.cgi: " + << gMaxAgentGroups << LL_ENDL; + } + else { + gMaxAgentGroups = DEFAULT_MAX_AGENT_GROUPS; + LL_INFOS("LLStartup") << "using gMaxAgentGroups default: " + << gMaxAgentGroups << LL_ENDL; + } + + bool success = false; + // JC: gesture loading done below, when we have an asset system + // in place. Don't delete/clear gUserCredentials until then. + if(gAgentID.notNull() + && gAgentSessionID.notNull() + && gMessageSystem->mOurCircuitCode + && gFirstSim.isOk() + && gInventory.getRootFolderID().notNull()) + { + success = true; + } + + return success; +} + +void transition_back_to_login_panel(const std::string& emsg) +{ + if (gNoRender) + { + LL_WARNS("AppInit") << "Failed to login!" << LL_ENDL; + LL_WARNS("AppInit") << emsg << LL_ENDL; + exit(0); + } + + // Bounce back to the login screen. + reset_login(); // calls LLStartUp::setStartupState( STATE_LOGIN_SHOW ); + gSavedSettings.setBOOL("AutoLogin", FALSE); +} diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 582f50ba37..a84346ab84 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -83,7 +83,7 @@ LLToolPie::LLToolPie() mMouseOutsideSlop( false ), mMouseSteerX(-1), mMouseSteerY(-1), - mAbortClickToWalk(false), + mBlockClickToWalk(false), mClickAction(0), mClickActionBuyEnabled( gSavedSettings.getBOOL("ClickActionBuyEnabled") ), mClickActionPayEnabled( gSavedSettings.getBOOL("ClickActionPayEnabled") ) @@ -303,7 +303,7 @@ BOOL LLToolPie::handleLeftClickPick() if (gFocusMgr.getKeyboardFocus()) { // don't click to walk on attempt to give focus to world - mAbortClickToWalk = true; + mBlockClickToWalk = true; gFocusMgr.setKeyboardFocus(NULL); } @@ -625,7 +625,7 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask) // let media have first pass at click if (handleMediaMouseUp() || LLViewerMediaFocus::getInstance()->getFocus()) { - mAbortClickToWalk = true; + mBlockClickToWalk = true; } stopCameraSteering(); mMouseButtonDown = false; @@ -633,7 +633,7 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask) if (click_action == CLICK_ACTION_NONE // not doing 1-click action && gSavedSettings.getBOOL("ClickToWalk") // click to walk enabled && !gAgent.getFlying() // don't auto-navigate while flying until that works - && !mAbortClickToWalk // another behavior hasn't cancelled click to walk + && !mBlockClickToWalk // another behavior hasn't cancelled click to walk && !mPick.mPosGlobal.isExactlyZero() // valid coordinates for pick && (mPick.mPickType == LLPickInfo::PICK_LAND // we clicked on land || mPick.mObjectID.notNull())) // or on an object @@ -658,11 +658,11 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask) mAutoPilotDestination = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, FALSE); mAutoPilotDestination->setPositionGlobal(mPick.mPosGlobal); mAutoPilotDestination->setPixelSize(5); - mAutoPilotDestination->setColor(LLColor4U(50, 50, 200)); + mAutoPilotDestination->setColor(LLColor4U(170, 210, 190)); mAutoPilotDestination->setDuration(3.f); handle_go_to(); - mAbortClickToWalk = false; + mBlockClickToWalk = false; return TRUE; } @@ -675,7 +675,7 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask) LLToolMgr::getInstance()->clearTransientTool(); gAgentCamera.setLookAt(LOOKAT_TARGET_CONVERSATION, obj); // maybe look at object/person clicked on - mAbortClickToWalk = false; + mBlockClickToWalk = false; return LLTool::handleMouseUp(x, y, mask); } @@ -1298,7 +1298,8 @@ void LLToolPie::VisitHomePage(const LLPickInfo& info) void LLToolPie::handleSelect() { - mAbortClickToWalk = true; + // tool is reselected when app gets focus, etc. + mBlockClickToWalk = true; } void LLToolPie::handleDeselect() @@ -1708,8 +1709,13 @@ void LLToolPie::showVisualContextMenuEffect() effectp->setDuration(0.25f); } +typedef enum e_near_far +{ + NEAR_INTERSECTION, + FAR_INTERSECTION +} ENearFar; -bool intersect_ray_with_sphere( const LLVector3& ray_pt, const LLVector3& ray_dir, const LLVector3& sphere_center, F32 sphere_radius, LLVector3& intersection_pt) +bool intersect_ray_with_sphere( const LLVector3& ray_pt, const LLVector3& ray_dir, const LLVector3& sphere_center, F32 sphere_radius, e_near_far near_far, LLVector3& intersection_pt) { // do ray/sphere intersection by solving quadratic equation LLVector3 sphere_to_ray_start_vec = ray_pt - sphere_center; @@ -1717,10 +1723,11 @@ bool intersect_ray_with_sphere( const LLVector3& ray_pt, const LLVector3& ray_di F32 C = sphere_to_ray_start_vec.lengthSquared() - (sphere_radius * sphere_radius); F32 discriminant = B*B - 4.f*C; - if (discriminant > 0.f) + if (discriminant >= 0.f) { // intersection detected, now find closest one F32 t0 = (-B - sqrtf(discriminant)) / 2.f; - if (t0 > 0.f) + + if (t0 > 0.f && near_far == NEAR_INTERSECTION) { intersection_pt = ray_pt + ray_dir * t0; } @@ -1731,14 +1738,16 @@ bool intersect_ray_with_sphere( const LLVector3& ray_pt, const LLVector3& ray_di } return true; } - - return false; + else + { // no intersection + return false; + } } void LLToolPie::startCameraSteering() { mMouseOutsideSlop = true; - mAbortClickToWalk = true; + mBlockClickToWalk = true; if (gAgentCamera.getFocusOnAvatar()) { @@ -1777,7 +1786,7 @@ void LLToolPie::startCameraSteering() if (mMouseSteerGrabPoint) { mMouseSteerGrabPoint->markDead(); } mMouseSteerGrabPoint = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, FALSE); mMouseSteerGrabPoint->setPositionGlobal(mSteerPick.mPosGlobal); - mMouseSteerGrabPoint->setColor(LLColor4U(50, 50, 200)); + mMouseSteerGrabPoint->setColor(LLColor4U(170, 210, 190)); mMouseSteerGrabPoint->setPixelSize(5); mMouseSteerGrabPoint->setDuration(2.f); } @@ -1785,64 +1794,80 @@ void LLToolPie::startCameraSteering() void LLToolPie::steerCameraWithMouse(S32 x, S32 y) { - const F32 MIN_ROTATION_RADIUS_FRACTION = 0.2f; - + const LLViewerCamera& camera = LLViewerCamera::instance(); + const LLCoordFrame& rotation_frame = gAgent.getFrameAgent(); const LLVector3 pick_pos = gAgent.getPosAgentFromGlobal(mSteerPick.mPosGlobal); - const LLVector3 rotation_center = gAgent.getFrameAgent().getOrigin(); - // FIXME: get this to work with camera tilt (i.e. sitting on a rotating object) - const LLVector3 rotation_up_axis(LLVector3::z_axis); - - LLVector3 object_rotation_center = rotation_center + parallel_component(pick_pos - rotation_center, rotation_up_axis); - F32 min_rotation_radius = MIN_ROTATION_RADIUS_FRACTION * dist_vec(rotation_center, LLViewerCamera::instance().getOrigin());; - F32 pick_distance_from_rotation_center = llclamp(dist_vec(pick_pos, object_rotation_center), min_rotation_radius, F32_MAX); + const LLVector3 pick_rotation_center = rotation_frame.getOrigin() + parallel_component(pick_pos - rotation_frame.getOrigin(), rotation_frame.getUpAxis()); + const F32 MIN_ROTATION_RADIUS_FRACTION = 0.2f; + const F32 min_rotation_radius = MIN_ROTATION_RADIUS_FRACTION * dist_vec(pick_rotation_center, camera.getOrigin());; + const F32 pick_distance_from_rotation_center = llclamp(dist_vec(pick_pos, pick_rotation_center), min_rotation_radius, F32_MAX); + const LLVector3 camera_to_rotation_center = pick_rotation_center - camera.getOrigin(); + const LLVector3 adjusted_camera_pos = LLViewerCamera::instance().getOrigin() + projected_vec(camera_to_rotation_center, rotation_frame.getUpAxis()); + const F32 camera_distance_from_rotation_center = dist_vec(adjusted_camera_pos, pick_rotation_center); - LLVector3 mouse_ray = orthogonal_component(gViewerWindow->mouseDirectionGlobal(x, y), rotation_up_axis); + LLVector3 mouse_ray = orthogonal_component(gViewerWindow->mouseDirectionGlobal(x, y), rotation_frame.getUpAxis()); mouse_ray.normalize(); - LLVector3 old_mouse_ray = orthogonal_component(gViewerWindow->mouseDirectionGlobal(mMouseSteerX, mMouseSteerY), rotation_up_axis); + LLVector3 old_mouse_ray = orthogonal_component(gViewerWindow->mouseDirectionGlobal(mMouseSteerX, mMouseSteerY), rotation_frame.getUpAxis()); old_mouse_ray.normalize(); - LLVector3 camera_pos = gAgentCamera.getCameraPositionAgent(); - LLVector3 camera_to_rotation_center = object_rotation_center - camera_pos; - LLVector3 adjusted_camera_pos = camera_pos + projected_vec(camera_to_rotation_center, rotation_up_axis); - LLVector3 rotation_fwd_axis = LLViewerCamera::instance().getAtAxis() - projected_vec(LLViewerCamera::instance().getAtAxis(), rotation_up_axis); - rotation_fwd_axis.normalize(); - F32 pick_dist = dist_vec(pick_pos, adjusted_camera_pos); - + F32 yaw_angle; + F32 old_yaw_angle; LLVector3 mouse_on_sphere; - bool mouse_hit_sphere = intersect_ray_with_sphere(adjusted_camera_pos + (mouse_ray * pick_dist * 1.1f), - -1.f * mouse_ray, - object_rotation_center, - pick_distance_from_rotation_center, - mouse_on_sphere); - LLVector3 old_mouse_on_sphere; - intersect_ray_with_sphere(adjusted_camera_pos + (old_mouse_ray * pick_dist * 1.1f), - -1.f * old_mouse_ray, - object_rotation_center, - pick_distance_from_rotation_center, - old_mouse_on_sphere); - if (mouse_hit_sphere) + if (intersect_ray_with_sphere( + adjusted_camera_pos, + mouse_ray, + pick_rotation_center, + pick_distance_from_rotation_center, + FAR_INTERSECTION, + mouse_on_sphere)) { - // calculate rotation frame in screen space - LLVector3 screen_rotation_up_axis = orthogonal_component(rotation_up_axis, LLViewerCamera::instance().getAtAxis()); - screen_rotation_up_axis.normalize(); - - LLVector3 screen_rotation_left_axis = screen_rotation_up_axis % LLViewerCamera::instance().getAtAxis(); + LLVector3 mouse_sphere_offset = mouse_on_sphere - pick_rotation_center; + yaw_angle = atan2f(mouse_sphere_offset * rotation_frame.getLeftAxis(), mouse_sphere_offset * rotation_frame.getAtAxis()); + } + else + { + yaw_angle = F_PI_BY_TWO + asinf(pick_distance_from_rotation_center / camera_distance_from_rotation_center); + if (mouse_ray * rotation_frame.getLeftAxis() < 0.f) + { + yaw_angle *= -1.f; + } + } - LLVector3 rotation_furthest_pt = object_rotation_center + pick_distance_from_rotation_center * rotation_fwd_axis; - F32 mouse_lateral_distance = llclamp(((mouse_on_sphere - rotation_furthest_pt) * screen_rotation_left_axis) / pick_distance_from_rotation_center, -1.f, 1.f); - F32 old_mouse_lateral_distance = llclamp(((old_mouse_on_sphere - rotation_furthest_pt) * screen_rotation_left_axis) / pick_distance_from_rotation_center, -1.f, 1.f); + if (intersect_ray_with_sphere( + adjusted_camera_pos, + old_mouse_ray, + pick_rotation_center, + pick_distance_from_rotation_center, + FAR_INTERSECTION, + old_mouse_on_sphere)) + { + LLVector3 mouse_sphere_offset = old_mouse_on_sphere - pick_rotation_center; + old_yaw_angle = atan2f(mouse_sphere_offset * rotation_frame.getLeftAxis(), mouse_sphere_offset * rotation_frame.getAtAxis()); + } + else + { + old_yaw_angle = F_PI_BY_TWO + asinf(pick_distance_from_rotation_center / camera_distance_from_rotation_center); - F32 yaw_angle = asinf(mouse_lateral_distance); - F32 old_yaw_angle = asinf(old_mouse_lateral_distance); + if (mouse_ray * rotation_frame.getLeftAxis() < 0.f) + { + old_yaw_angle *= -1.f; + } + } - F32 delta_angle = yaw_angle - old_yaw_angle; - if (!mClockwise) delta_angle *= -1.f; + const F32 delta_angle = yaw_angle - old_yaw_angle; + if (mClockwise) + { gAgent.yaw(delta_angle); - mMouseSteerX = x; - mMouseSteerY = y; } + else + { + gAgent.yaw(-delta_angle); + } + + mMouseSteerX = x; + mMouseSteerY = y; } diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h index 22e77a3159..22359a6db8 100644 --- a/indra/newview/lltoolpie.h +++ b/indra/newview/lltoolpie.h @@ -66,6 +66,7 @@ public: LLViewerObject* getClickActionObject() { return mClickActionObject; } LLObjectSelection* getLeftClickSelection() { return (LLObjectSelection*)mLeftClickSelection; } void resetSelection(); + void blockClickToWalk() { mBlockClickToWalk = true; } static void selectionPropertiesReceived(); @@ -105,7 +106,7 @@ private: LLPointer<LLHUDEffectBlob> mAutoPilotDestination; LLPointer<LLHUDEffectBlob> mMouseSteerGrabPoint; bool mClockwise; - bool mAbortClickToWalk; + bool mBlockClickToWalk; LLUUID mMediaMouseCaptureID; LLPickInfo mPick; LLPickInfo mHoverPick; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 75cf2efc69..33fff82738 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -1,8183 +1,8189 @@ -/** - * @file llviewermenu.cpp - * @brief Builds menus out of items. - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" -#include "llviewermenu.h" - -// linden library includes -#include "llavatarnamecache.h" // IDEVO -#include "llfloaterreg.h" -#include "llcombobox.h" -#include "llinventorypanel.h" -#include "llnotifications.h" -#include "llnotificationsutil.h" - -// newview includes -#include "llagent.h" -#include "llagentcamera.h" -#include "llagentwearables.h" -#include "llagentpilot.h" -#include "llbottomtray.h" -#include "llcompilequeue.h" -#include "llconsole.h" -#include "lldebugview.h" -#include "llfilepicker.h" -#include "llfirstuse.h" -#include "llfloaterbuy.h" -#include "llfloaterbuycontents.h" -#include "llbuycurrencyhtml.h" -#include "llfloatergodtools.h" -#include "llfloaterinventory.h" -#include "llfloaterland.h" -#include "llfloaterpay.h" -#include "llfloaterreporter.h" -#include "llfloatersearch.h" -#include "llfloaterscriptdebug.h" -#include "llfloatersnapshot.h" -#include "llfloatertools.h" -#include "llfloaterworldmap.h" -#include "llavataractions.h" -#include "lllandmarkactions.h" -#include "llgroupmgr.h" -#include "lltooltip.h" -#include "llhints.h" -#include "llhudeffecttrail.h" -#include "llhudmanager.h" -#include "llimview.h" -#include "llinventorybridge.h" -#include "llinventorydefines.h" -#include "llinventoryfunctions.h" -#include "llpanellogin.h" -#include "llpanelblockedlist.h" -#include "llmenucommands.h" -#include "llmoveview.h" -#include "llparcel.h" -#include "llrootview.h" -#include "llselectmgr.h" -#include "llsidetray.h" -#include "llstatusbar.h" -#include "lltextureview.h" -#include "lltoolcomp.h" -#include "lltoolmgr.h" -#include "lltoolpie.h" -#include "lltoolselectland.h" -#include "lltrans.h" -#include "llviewergenericmessage.h" -#include "llviewerhelp.h" -#include "llviewermenufile.h" // init_menu_file() -#include "llviewermessage.h" -#include "llviewernetwork.h" -#include "llviewerobjectlist.h" -#include "llviewerparcelmgr.h" -#include "llviewerstats.h" -#include "llvoavatarself.h" -#include "llworldmap.h" -#include "pipeline.h" -#include "llviewerjoystick.h" -#include "llwlanimator.h" -#include "llwlparammanager.h" -#include "llfloatercamera.h" -#include "lluilistener.h" -#include "llappearancemgr.h" -#include "lltrans.h" -#include "lleconomy.h" -#include "boost/unordered_map.hpp" - -using namespace LLVOAvatarDefines; - -static boost::unordered_map<std::string, LLStringExplicit> sDefaultItemLabels; - -BOOL enable_land_build(void*); -BOOL enable_object_build(void*); - -LLVOAvatar* find_avatar_from_object( LLViewerObject* object ); -LLVOAvatar* find_avatar_from_object( const LLUUID& object_id ); - -void handle_test_load_url(void*); - -// -// Evil hackish imported globals - -//extern BOOL gHideSelectedObjects; -//extern BOOL gAllowSelectAvatar; -//extern BOOL gDebugAvatarRotation; -extern BOOL gDebugClicks; -extern BOOL gDebugWindowProc; -//extern BOOL gDebugTextEditorTips; -//extern BOOL gDebugSelectMgr; - -// -// Globals -// - -LLMenuBarGL *gMenuBarView = NULL; -LLViewerMenuHolderGL *gMenuHolder = NULL; -LLMenuGL *gPopupMenuView = NULL; -LLMenuGL *gEditMenu = NULL; -LLMenuBarGL *gLoginMenuBarView = NULL; - -// Pie menus -LLContextMenu *gMenuAvatarSelf = NULL; -LLContextMenu *gMenuAvatarOther = NULL; -LLContextMenu *gMenuObject = NULL; -LLContextMenu *gMenuAttachmentSelf = NULL; -LLContextMenu *gMenuAttachmentOther = NULL; -LLContextMenu *gMenuLand = NULL; - -const std::string SAVE_INTO_INVENTORY("Save Object Back to My Inventory"); -const std::string SAVE_INTO_TASK_INVENTORY("Save Object Back to Object Contents"); - -LLMenuGL* gAttachSubMenu = NULL; -LLMenuGL* gDetachSubMenu = NULL; -LLMenuGL* gTakeOffClothes = NULL; -LLContextMenu* gAttachScreenPieMenu = NULL; -LLContextMenu* gAttachPieMenu = NULL; -LLContextMenu* gAttachBodyPartPieMenus[8]; -LLContextMenu* gDetachPieMenu = NULL; -LLContextMenu* gDetachScreenPieMenu = NULL; -LLContextMenu* gDetachBodyPartPieMenus[8]; - -LLMenuItemCallGL* gAFKMenu = NULL; -LLMenuItemCallGL* gBusyMenu = NULL; - -// -// Local prototypes - -// File Menu -const char* upload_pick(void* data); -void handle_compress_image(void*); - - -// Edit menu -void handle_dump_group_info(void *); -void handle_dump_capabilities_info(void *); - -// Advanced->Consoles menu -void handle_region_dump_settings(void*); -void handle_region_dump_temp_asset_data(void*); -void handle_region_clear_temp_asset_data(void*); - -// Object pie menu -BOOL sitting_on_selection(); - -void near_sit_object(); -//void label_sit_or_stand(std::string& label, void*); -// buy and take alias into the same UI positions, so these -// declarations handle this mess. -BOOL is_selection_buy_not_take(); -S32 selection_price(); -BOOL enable_take(); -void handle_take(); -void handle_object_show_inspector(); -void handle_avatar_show_inspector(); -bool confirm_take(const LLSD& notification, const LLSD& response); - -void handle_buy_object(LLSaleInfo sale_info); -void handle_buy_contents(LLSaleInfo sale_info); - -// Land pie menu -void near_sit_down_point(BOOL success, void *); - -// Avatar pie menu - -// Debug menu - - -void velocity_interpolate( void* ); - -void handle_rebake_textures(void*); -BOOL check_admin_override(void*); -void handle_admin_override_toggle(void*); -#ifdef TOGGLE_HACKED_GODLIKE_VIEWER -void handle_toggle_hacked_godmode(void*); -BOOL check_toggle_hacked_godmode(void*); -bool enable_toggle_hacked_godmode(void*); -#endif - -void toggle_show_xui_names(void *); -BOOL check_show_xui_names(void *); - -// Debug UI - -void handle_buy_currency_test(void*); - -void handle_god_mode(void*); - -// God menu -void handle_leave_god_mode(void*); - - -void handle_reset_view(); - -void handle_duplicate_in_place(void*); - - -void handle_object_owner_self(void*); -void handle_object_owner_permissive(void*); -void handle_object_lock(void*); -void handle_object_asset_ids(void*); -void force_take_copy(void*); -#ifdef _CORY_TESTING -void force_export_copy(void*); -void force_import_geometry(void*); -#endif - -void handle_force_parcel_owner_to_me(void*); -void handle_force_parcel_to_content(void*); -void handle_claim_public_land(void*); - -void handle_god_request_avatar_geometry(void *); // Hack for easy testing of new avatar geometry -void reload_vertex_shader(void *); -void handle_disconnect_viewer(void *); - -void force_error_breakpoint(void *); -void force_error_llerror(void *); -void force_error_bad_memory_access(void *); -void force_error_infinite_loop(void *); -void force_error_software_exception(void *); -void force_error_driver_crash(void *); - -void handle_force_delete(void*); -void print_object_info(void*); -void print_agent_nvpairs(void*); -void toggle_debug_menus(void*); -void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExtStat ext_status); -void dump_select_mgr(void*); - -void dump_inventory(void*); -void toggle_visibility(void*); -BOOL get_visibility(void*); - -// Avatar Pie menu -void request_friendship(const LLUUID& agent_id); - -// Tools menu -void handle_selected_texture_info(void*); - -void handle_dump_followcam(void*); -void handle_viewer_enable_message_log(void*); -void handle_viewer_disable_message_log(void*); - -BOOL enable_buy_land(void*); - -// Help menu - -void handle_test_male(void *); -void handle_test_female(void *); -void handle_toggle_pg(void*); -void handle_dump_attachments(void *); -void handle_dump_avatar_local_textures(void*); -void handle_debug_avatar_textures(void*); -void handle_grab_baked_texture(void*); -BOOL enable_grab_baked_texture(void*); -void handle_dump_region_object_cache(void*); - -BOOL enable_save_into_inventory(void*); -BOOL enable_save_into_task_inventory(void*); - -BOOL enable_detach(const LLSD& = LLSD()); -void menu_toggle_attached_lights(void* user_data); -void menu_toggle_attached_particles(void* user_data); - -class LLMenuParcelObserver : public LLParcelObserver -{ -public: - LLMenuParcelObserver(); - ~LLMenuParcelObserver(); - virtual void changed(); -}; - -static LLMenuParcelObserver* gMenuParcelObserver = NULL; - -static LLUIListener sUIListener; - -LLMenuParcelObserver::LLMenuParcelObserver() -{ - LLViewerParcelMgr::getInstance()->addObserver(this); -} - -LLMenuParcelObserver::~LLMenuParcelObserver() -{ - LLViewerParcelMgr::getInstance()->removeObserver(this); -} - -void LLMenuParcelObserver::changed() -{ - gMenuHolder->childSetEnabled("Land Buy Pass", LLPanelLandGeneral::enableBuyPass(NULL)); - - BOOL buyable = enable_buy_land(NULL); - gMenuHolder->childSetEnabled("Land Buy", buyable); - gMenuHolder->childSetEnabled("Buy Land...", buyable); -} - - -void initialize_menus(); - -//----------------------------------------------------------------------------- -// Initialize main menus -// -// HOW TO NAME MENUS: -// -// First Letter Of Each Word Is Capitalized, Even At Or And -// -// Items that lead to dialog boxes end in "..." -// -// Break up groups of more than 6 items with separators -//----------------------------------------------------------------------------- - -void set_underclothes_menu_options() -{ - if (gMenuHolder && gAgent.isTeen()) - { - gMenuHolder->getChild<LLView>("Self Underpants")->setVisible(FALSE); - gMenuHolder->getChild<LLView>("Self Undershirt")->setVisible(FALSE); - } - if (gMenuBarView && gAgent.isTeen()) - { - gMenuBarView->getChild<LLView>("Menu Underpants")->setVisible(FALSE); - gMenuBarView->getChild<LLView>("Menu Undershirt")->setVisible(FALSE); - } -} - -void init_menus() -{ - S32 top = gViewerWindow->getRootView()->getRect().getHeight(); - - // Initialize actions - initialize_menus(); - - /// - /// Popup menu - /// - /// The popup menu is now populated by the show_context_menu() - /// method. - - LLMenuGL::Params menu_params; - menu_params.name = "Popup"; - menu_params.visible = false; - gPopupMenuView = LLUICtrlFactory::create<LLMenuGL>(menu_params); - gMenuHolder->addChild( gPopupMenuView ); - - /// - /// Context menus - /// - - const widget_registry_t& registry = - LLViewerMenuHolderGL::child_registry_t::instance(); - gEditMenu = LLUICtrlFactory::createFromFile<LLMenuGL>("menu_edit.xml", gMenuHolder, registry); - gMenuAvatarSelf = LLUICtrlFactory::createFromFile<LLContextMenu>( - "menu_avatar_self.xml", gMenuHolder, registry); - gMenuAvatarOther = LLUICtrlFactory::createFromFile<LLContextMenu>( - "menu_avatar_other.xml", gMenuHolder, registry); - - gDetachScreenPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Detach HUD", true); - gDetachPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Detach", true); - - gMenuObject = LLUICtrlFactory::createFromFile<LLContextMenu>( - "menu_object.xml", gMenuHolder, registry); - - gAttachScreenPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Attach HUD"); - gAttachPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Attach"); - - gMenuAttachmentSelf = LLUICtrlFactory::createFromFile<LLContextMenu>( - "menu_attachment_self.xml", gMenuHolder, registry); - gMenuAttachmentOther = LLUICtrlFactory::createFromFile<LLContextMenu>( - "menu_attachment_other.xml", gMenuHolder, registry); - - gMenuLand = LLUICtrlFactory::createFromFile<LLContextMenu>( - "menu_land.xml", gMenuHolder, registry); - - /// - /// set up the colors - /// - LLColor4 color; - - LLColor4 context_menu_color = LLUIColorTable::instance().getColor("MenuPopupBgColor"); - - gMenuAvatarSelf->setBackgroundColor( context_menu_color ); - gMenuAvatarOther->setBackgroundColor( context_menu_color ); - gMenuObject->setBackgroundColor( context_menu_color ); - gMenuAttachmentSelf->setBackgroundColor( context_menu_color ); - gMenuAttachmentOther->setBackgroundColor( context_menu_color ); - - gMenuLand->setBackgroundColor( context_menu_color ); - - color = LLUIColorTable::instance().getColor( "MenuPopupBgColor" ); - gPopupMenuView->setBackgroundColor( color ); - - // If we are not in production, use a different color to make it apparent. - if (LLGridManager::getInstance()->isInProductionGrid()) - { - color = LLUIColorTable::instance().getColor( "MenuBarBgColor" ); - } - else - { - color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" ); - } - gMenuBarView = LLUICtrlFactory::getInstance()->createFromFile<LLMenuBarGL>("menu_viewer.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - gMenuBarView->setRect(LLRect(0, top, 0, top - MENU_BAR_HEIGHT)); - gMenuBarView->setBackgroundColor( color ); - - LLView* menu_bar_holder = gViewerWindow->getRootView()->getChildView("menu_bar_holder"); - menu_bar_holder->addChild(gMenuBarView); - - gViewerWindow->setMenuBackgroundColor(false, - LLGridManager::getInstance()->isInProductionGrid()); - - // Assume L$10 for now, the server will tell us the real cost at login - // *TODO:Also fix cost in llfolderview.cpp for Inventory menus - const std::string upload_cost("10"); - gMenuHolder->childSetLabelArg("Upload Image", "[COST]", upload_cost); - gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", upload_cost); - gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", upload_cost); - gMenuHolder->childSetLabelArg("Bulk Upload", "[COST]", upload_cost); - - gAFKMenu = gMenuBarView->getChild<LLMenuItemCallGL>("Set Away", TRUE); - gBusyMenu = gMenuBarView->getChild<LLMenuItemCallGL>("Set Busy", TRUE); - gAttachSubMenu = gMenuBarView->findChildMenuByName("Attach Object", TRUE); - gDetachSubMenu = gMenuBarView->findChildMenuByName("Detach Object", TRUE); - -#if !MEM_TRACK_MEM - // Don't display the Memory console menu if the feature is turned off - LLMenuItemCheckGL *memoryMenu = gMenuBarView->getChild<LLMenuItemCheckGL>("Memory", TRUE); - if (memoryMenu) - { - memoryMenu->setVisible(FALSE); - } -#endif - - gMenuBarView->createJumpKeys(); - - // Let land based option enable when parcel changes - gMenuParcelObserver = new LLMenuParcelObserver(); - - gLoginMenuBarView = LLUICtrlFactory::getInstance()->createFromFile<LLMenuBarGL>("menu_login.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - gLoginMenuBarView->arrangeAndClear(); - LLRect menuBarRect = gLoginMenuBarView->getRect(); - menuBarRect.setLeftTopAndSize(0, menu_bar_holder->getRect().getHeight(), menuBarRect.getWidth(), menuBarRect.getHeight()); - gLoginMenuBarView->setRect(menuBarRect); - gLoginMenuBarView->setBackgroundColor( color ); - menu_bar_holder->addChild(gLoginMenuBarView); - - // tooltips are on top of EVERYTHING, including menus - gViewerWindow->getRootView()->sendChildToFront(gToolTipView); -} - -/////////////////// -// SHOW CONSOLES // -/////////////////// - - -class LLAdvancedToggleConsole : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string console_type = userdata.asString(); - if ("texture" == console_type) - { - toggle_visibility( (void*)gTextureView ); - } - else if ("debug" == console_type) - { - toggle_visibility( (void*)static_cast<LLUICtrl*>(gDebugView->mDebugConsolep)); - } - else if (gTextureSizeView && "texture size" == console_type) - { - toggle_visibility( (void*)gTextureSizeView ); - } - else if (gTextureCategoryView && "texture category" == console_type) - { - toggle_visibility( (void*)gTextureCategoryView ); - } - else if ("fast timers" == console_type) - { - toggle_visibility( (void*)gDebugView->mFastTimerView ); - } -#if MEM_TRACK_MEM - else if ("memory view" == console_type) - { - toggle_visibility( (void*)gDebugView->mMemoryView ); - } -#endif - return true; - } -}; -class LLAdvancedCheckConsole : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string console_type = userdata.asString(); - bool new_value = false; - if ("texture" == console_type) - { - new_value = get_visibility( (void*)gTextureView ); - } - else if ("debug" == console_type) - { - new_value = get_visibility( (void*)((LLView*)gDebugView->mDebugConsolep) ); - } - else if (gTextureSizeView && "texture size" == console_type) - { - new_value = get_visibility( (void*)gTextureSizeView ); - } - else if (gTextureCategoryView && "texture category" == console_type) - { - new_value = get_visibility( (void*)gTextureCategoryView ); - } - else if ("fast timers" == console_type) - { - new_value = get_visibility( (void*)gDebugView->mFastTimerView ); - } -#if MEM_TRACK_MEM - else if ("memory view" == console_type) - { - new_value = get_visibility( (void*)gDebugView->mMemoryView ); - } -#endif - - return new_value; - } -}; - - -////////////////////////// -// DUMP INFO TO CONSOLE // -////////////////////////// - - -class LLAdvancedDumpInfoToConsole : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string info_type = userdata.asString(); - if ("region" == info_type) - { - handle_region_dump_settings(NULL); - } - else if ("group" == info_type) - { - handle_dump_group_info(NULL); - } - else if ("capabilities" == info_type) - { - handle_dump_capabilities_info(NULL); - } - return true; - } -}; - - -////////////// -// HUD INFO // -////////////// - - -class LLAdvancedToggleHUDInfo : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string info_type = userdata.asString(); - - if ("camera" == info_type) - { - gDisplayCameraPos = !(gDisplayCameraPos); - } - else if ("wind" == info_type) - { - gDisplayWindInfo = !(gDisplayWindInfo); - } - else if ("fov" == info_type) - { - gDisplayFOV = !(gDisplayFOV); - } - else if ("badge" == info_type) - { - gDisplayBadge = !(gDisplayBadge); - } - return true; - } -}; - -class LLAdvancedCheckHUDInfo : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string info_type = userdata.asString(); - bool new_value = false; - if ("camera" == info_type) - { - new_value = gDisplayCameraPos; - } - else if ("wind" == info_type) - { - new_value = gDisplayWindInfo; - } - else if ("fov" == info_type) - { - new_value = gDisplayFOV; - } - else if ("badge" == info_type) - { - new_value = gDisplayBadge; - } - return new_value; - } -}; - - -////////////// -// FLYING // -////////////// - -class LLAdvancedAgentFlyingInfo : public view_listener_t -{ - bool handleEvent(const LLSD&) - { - return gAgent.getFlying(); - } -}; - - -/////////////////////// -// CLEAR GROUP CACHE // -/////////////////////// - -class LLAdvancedClearGroupCache : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLGroupMgr::debugClearAllGroups(NULL); - return true; - } -}; - - - - -///////////////// -// RENDER TYPE // -///////////////// -U32 render_type_from_string(std::string render_type) -{ - if ("simple" == render_type) - { - return LLPipeline::RENDER_TYPE_SIMPLE; - } - else if ("alpha" == render_type) - { - return LLPipeline::RENDER_TYPE_ALPHA; - } - else if ("tree" == render_type) - { - return LLPipeline::RENDER_TYPE_TREE; - } - else if ("character" == render_type) - { - return LLPipeline::RENDER_TYPE_AVATAR; - } - else if ("surfacePath" == render_type) - { - return LLPipeline::RENDER_TYPE_TERRAIN; - } - else if ("sky" == render_type) - { - return LLPipeline::RENDER_TYPE_SKY; - } - else if ("water" == render_type) - { - return LLPipeline::RENDER_TYPE_WATER; - } - else if ("ground" == render_type) - { - return LLPipeline::RENDER_TYPE_GROUND; - } - else if ("volume" == render_type) - { - return LLPipeline::RENDER_TYPE_VOLUME; - } - else if ("grass" == render_type) - { - return LLPipeline::RENDER_TYPE_GRASS; - } - else if ("clouds" == render_type) - { - return LLPipeline::RENDER_TYPE_CLOUDS; - } - else if ("particles" == render_type) - { - return LLPipeline::RENDER_TYPE_PARTICLES; - } - else if ("bump" == render_type) - { - return LLPipeline::RENDER_TYPE_BUMP; - } - else - { - return 0; - } -} - - -class LLAdvancedToggleRenderType : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - U32 render_type = render_type_from_string( userdata.asString() ); - if ( render_type != 0 ) - { - LLPipeline::toggleRenderTypeControl( (void*)render_type ); - } - return true; - } -}; - - -class LLAdvancedCheckRenderType : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - U32 render_type = render_type_from_string( userdata.asString() ); - bool new_value = false; - - if ( render_type != 0 ) - { - new_value = LLPipeline::hasRenderTypeControl( (void*)render_type ); - } - - return new_value; - } -}; - - -///////////// -// FEATURE // -///////////// -U32 feature_from_string(std::string feature) -{ - if ("ui" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_UI; - } - else if ("selected" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_SELECTED; - } - else if ("highlighted" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_HIGHLIGHTED; - } - else if ("dynamic textures" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES; - } - else if ("foot shadows" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS; - } - else if ("fog" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_FOG; - } - else if ("fr info" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_FR_INFO; - } - else if ("flexible" == feature) - { - return LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE; - } - else - { - return 0; - } -}; - - -class LLAdvancedToggleFeature : public view_listener_t{ - bool handleEvent(const LLSD& userdata) - { - U32 feature = feature_from_string( userdata.asString() ); - if ( feature != 0 ) - { - LLPipeline::toggleRenderDebugFeature( (void*)feature ); - } - return true; - } -}; - -class LLAdvancedCheckFeature : public view_listener_t -{bool handleEvent(const LLSD& userdata) -{ - U32 feature = feature_from_string( userdata.asString() ); - bool new_value = false; - - if ( feature != 0 ) - { - new_value = LLPipeline::toggleRenderDebugFeatureControl( (void*)feature ); - } - - return new_value; -} -}; - -void toggle_destination_and_avatar_picker(const LLSD& show) -{ - S32 panel_idx = show.isDefined() ? show.asInteger() : -1; - LLView* container = gViewerWindow->getRootView()->getChildView("avatar_picker_and_destination_guide_container"); - LLMediaCtrl* destinations = container->findChild<LLMediaCtrl>("destination_guide_contents"); - LLMediaCtrl* avatar_picker = container->findChild<LLMediaCtrl>("avatar_picker_contents"); - LLButton* avatar_btn = gViewerWindow->getRootView()->getChildView("bottom_tray")->getChild<LLButton>("avatar_btn"); - LLButton* destination_btn = gViewerWindow->getRootView()->getChildView("bottom_tray")->getChild<LLButton>("destination_btn"); - - switch(panel_idx) - { - case 0: - if (!destinations->getVisible()) - { - container->setVisible(true); - destinations->setVisible(true); - avatar_picker->setVisible(false); - LLFirstUse::notUsingDestinationGuide(false); - avatar_btn->setToggleState(false); - destination_btn->setToggleState(true); - return; - } - break; - case 1: - if (!avatar_picker->getVisible()) - { - container->setVisible(true); - destinations->setVisible(false); - avatar_picker->setVisible(true); - avatar_btn->setToggleState(true); - destination_btn->setToggleState(false); - return; - } - break; - default: - break; - } - - container->setVisible(false); - destinations->setVisible(false); - avatar_picker->setVisible(false); - avatar_btn->setToggleState(false); - destination_btn->setToggleState(false); -}; - - -////////////////// -// INFO DISPLAY // -////////////////// -U32 info_display_from_string(std::string info_display) -{ - if ("verify" == info_display) - { - return LLPipeline::RENDER_DEBUG_VERIFY; - } - else if ("bboxes" == info_display) - { - return LLPipeline::RENDER_DEBUG_BBOXES; - } - else if ("points" == info_display) - { - return LLPipeline::RENDER_DEBUG_POINTS; - } - else if ("octree" == info_display) - { - return LLPipeline::RENDER_DEBUG_OCTREE; - } - else if ("shadow frusta" == info_display) - { - return LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA; - } - else if ("occlusion" == info_display) - { - return LLPipeline::RENDER_DEBUG_OCCLUSION; - } - else if ("render batches" == info_display) - { - return LLPipeline::RENDER_DEBUG_BATCH_SIZE; - } - else if ("update type" == info_display) - { - return LLPipeline::RENDER_DEBUG_UPDATE_TYPE; - } - else if ("texture anim" == info_display) - { - return LLPipeline::RENDER_DEBUG_TEXTURE_ANIM; - } - else if ("texture priority" == info_display) - { - return LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY; - } - else if ("shame" == info_display) - { - return LLPipeline::RENDER_DEBUG_SHAME; - } - else if ("texture area" == info_display) - { - return LLPipeline::RENDER_DEBUG_TEXTURE_AREA; - } - else if ("face area" == info_display) - { - return LLPipeline::RENDER_DEBUG_FACE_AREA; - } - else if ("lights" == info_display) - { - return LLPipeline::RENDER_DEBUG_LIGHTS; - } - else if ("particles" == info_display) - { - return LLPipeline::RENDER_DEBUG_PARTICLES; - } - else if ("composition" == info_display) - { - return LLPipeline::RENDER_DEBUG_COMPOSITION; - } - else if ("glow" == info_display) - { - return LLPipeline::RENDER_DEBUG_GLOW; - } - else if ("collision skeleton" == info_display) - { - return LLPipeline::RENDER_DEBUG_AVATAR_VOLUME; - } - else if ("raycast" == info_display) - { - return LLPipeline::RENDER_DEBUG_RAYCAST; - } - else if ("agent target" == info_display) - { - return LLPipeline::RENDER_DEBUG_AGENT_TARGET; - } - else - { - return 0; - } -}; - -class LLAdvancedToggleInfoDisplay : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - U32 info_display = info_display_from_string( userdata.asString() ); - - if ( info_display != 0 ) - { - LLPipeline::toggleRenderDebug( (void*)info_display ); - } - - return true; - } -}; - - -class LLAdvancedCheckInfoDisplay : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - U32 info_display = info_display_from_string( userdata.asString() ); - bool new_value = false; - - if ( info_display != 0 ) - { - new_value = LLPipeline::toggleRenderDebugControl( (void*)info_display ); - } - - return new_value; - } -}; - - -/////////////////////////// -//// RANDOMIZE FRAMERATE // -/////////////////////////// - - -class LLAdvancedToggleRandomizeFramerate : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - gRandomizeFramerate = !(gRandomizeFramerate); - return true; - } -}; - -class LLAdvancedCheckRandomizeFramerate : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = gRandomizeFramerate; - return new_value; - } -}; - -void run_vectorize_perf_test(void *) -{ - gSavedSettings.setBOOL("VectorizePerfTest", TRUE); -} - - -//////////////////////////////// -// RUN Vectorized Perform Test// -//////////////////////////////// - - -class LLAdvancedVectorizePerfTest : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - run_vectorize_perf_test(NULL); - return true; - } -}; - -/////////////////////////// -//// PERIODIC SLOW FRAME // -/////////////////////////// - - -class LLAdvancedTogglePeriodicSlowFrame : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - gPeriodicSlowFrame = !(gPeriodicSlowFrame); - return true; - } -}; - -class LLAdvancedCheckPeriodicSlowFrame : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = gPeriodicSlowFrame; - return new_value; - } -}; - - - -//////////////// -// FRAME TEST // -//////////////// - - -class LLAdvancedToggleFrameTest : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLPipeline::sRenderFrameTest = !(LLPipeline::sRenderFrameTest); - return true; - } -}; - -class LLAdvancedCheckFrameTest : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLPipeline::sRenderFrameTest; - return new_value; - } -}; - - -/////////////////////////// -// SELECTED TEXTURE INFO // -/////////////////////////// - - -class LLAdvancedSelectedTextureInfo : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_selected_texture_info(NULL); - return true; - } -}; - -////////////////////// -// TOGGLE WIREFRAME // -////////////////////// - -class LLAdvancedToggleWireframe : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - gUseWireframe = !(gUseWireframe); - LLPipeline::updateRenderDeferred(); - gPipeline.resetVertexBuffers(); - return true; - } -}; - -class LLAdvancedCheckWireframe : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = gUseWireframe; - return new_value; - } -}; - -////////////////////// -// TEXTURE ATLAS // -////////////////////// - -class LLAdvancedToggleTextureAtlas : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLViewerTexture::sUseTextureAtlas = !LLViewerTexture::sUseTextureAtlas; - gSavedSettings.setBOOL("EnableTextureAtlas", LLViewerTexture::sUseTextureAtlas) ; - return true; - } -}; - -class LLAdvancedCheckTextureAtlas : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLViewerTexture::sUseTextureAtlas; // <-- make this using LLCacheControl - return new_value; - } -}; - -////////////////////////// -// DUMP SCRIPTED CAMERA // -////////////////////////// - -class LLAdvancedDumpScriptedCamera : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_dump_followcam(NULL); - return true; -} -}; - - - -////////////////////////////// -// DUMP REGION OBJECT CACHE // -////////////////////////////// - - -class LLAdvancedDumpRegionObjectCache : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) -{ - handle_dump_region_object_cache(NULL); - return true; - } -}; - -class LLAdvancedBuyCurrencyTest : public view_listener_t - { - bool handleEvent(const LLSD& userdata) - { - handle_buy_currency_test(NULL); - return true; - } -}; - - -///////////////////// -// DUMP SELECT MGR // -///////////////////// - - -class LLAdvancedDumpSelectMgr : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - dump_select_mgr(NULL); - return true; - } -}; - - - -//////////////////// -// DUMP INVENTORY // -//////////////////// - - -class LLAdvancedDumpInventory : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - dump_inventory(NULL); - return true; - } -}; - - - -//////////////////////////////// -// PRINT SELECTED OBJECT INFO // -//////////////////////////////// - - -class LLAdvancedPrintSelectedObjectInfo : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - print_object_info(NULL); - return true; - } -}; - - - -////////////////////// -// PRINT AGENT INFO // -////////////////////// - - -class LLAdvancedPrintAgentInfo : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - print_agent_nvpairs(NULL); - return true; - } -}; - - - -//////////////////////////////// -// PRINT TEXTURE MEMORY STATS // -//////////////////////////////// - - -class LLAdvancedPrintTextureMemoryStats : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - output_statistics(NULL); - return true; - } -}; - -////////////////// -// DEBUG CLICKS // -////////////////// - - -class LLAdvancedToggleDebugClicks : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - gDebugClicks = !(gDebugClicks); - return true; - } -}; - -class LLAdvancedCheckDebugClicks : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = gDebugClicks; - return new_value; - } -}; - - - -///////////////// -// DEBUG VIEWS // -///////////////// - - -class LLAdvancedToggleDebugViews : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLView::sDebugRects = !(LLView::sDebugRects); - return true; - } -}; - -class LLAdvancedCheckDebugViews : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLView::sDebugRects; - return new_value; - } -}; - - - -/////////////////////// -// XUI NAME TOOLTIPS // -/////////////////////// - - -class LLAdvancedToggleXUINameTooltips : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - toggle_show_xui_names(NULL); - return true; - } -}; - -class LLAdvancedCheckXUINameTooltips : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = check_show_xui_names(NULL); - return new_value; - } -}; - - - -//////////////////////// -// DEBUG MOUSE EVENTS // -//////////////////////// - - -class LLAdvancedToggleDebugMouseEvents : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLView::sDebugMouseHandling = !(LLView::sDebugMouseHandling); - return true; - } -}; - -class LLAdvancedCheckDebugMouseEvents : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLView::sDebugMouseHandling; - return new_value; - } -}; - - - -//////////////// -// DEBUG KEYS // -//////////////// - - -class LLAdvancedToggleDebugKeys : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLView::sDebugKeys = !(LLView::sDebugKeys); - return true; - } -}; - -class LLAdvancedCheckDebugKeys : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLView::sDebugKeys; - return new_value; - } -}; - - - -/////////////////////// -// DEBUG WINDOW PROC // -/////////////////////// - - -class LLAdvancedToggleDebugWindowProc : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - gDebugWindowProc = !(gDebugWindowProc); - return true; - } -}; - -class LLAdvancedCheckDebugWindowProc : public view_listener_t - { - bool handleEvent(const LLSD& userdata) - { - bool new_value = gDebugWindowProc; - return new_value; - } -}; - -// ------------------------------XUI MENU --------------------------- - -class LLAdvancedSendTestIms : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLIMModel::instance().testMessages(); - return true; -} -}; - - -/////////////// -// XUI NAMES // -/////////////// - - -class LLAdvancedToggleXUINames : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - toggle_show_xui_names(NULL); - return true; - } -}; - -class LLAdvancedCheckXUINames : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = check_show_xui_names(NULL); - return new_value; - } -}; - - -//////////////////////// -// GRAB BAKED TEXTURE // -//////////////////////// - - -class LLAdvancedGrabBakedTexture : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string texture_type = userdata.asString(); - if ("iris" == texture_type) - { - handle_grab_baked_texture( (void*)BAKED_EYES ); - } - else if ("head" == texture_type) - { - handle_grab_baked_texture( (void*)BAKED_HEAD ); - } - else if ("upper" == texture_type) - { - handle_grab_baked_texture( (void*)BAKED_UPPER ); - } - else if ("lower" == texture_type) - { - handle_grab_baked_texture( (void*)BAKED_LOWER ); - } - else if ("skirt" == texture_type) - { - handle_grab_baked_texture( (void*)BAKED_SKIRT ); - } - else if ("hair" == texture_type) - { - handle_grab_baked_texture( (void*)BAKED_HAIR ); - } - - return true; - } -}; - -class LLAdvancedEnableGrabBakedTexture : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) -{ - std::string texture_type = userdata.asString(); - bool new_value = false; - - if ("iris" == texture_type) - { - new_value = enable_grab_baked_texture( (void*)BAKED_EYES ); - } - else if ("head" == texture_type) - { - new_value = enable_grab_baked_texture( (void*)BAKED_HEAD ); - } - else if ("upper" == texture_type) - { - new_value = enable_grab_baked_texture( (void*)BAKED_UPPER ); - } - else if ("lower" == texture_type) - { - new_value = enable_grab_baked_texture( (void*)BAKED_LOWER ); - } - else if ("skirt" == texture_type) - { - new_value = enable_grab_baked_texture( (void*)BAKED_SKIRT ); - } - else if ("hair" == texture_type) - { - new_value = enable_grab_baked_texture( (void*)BAKED_HAIR ); - } - - return new_value; -} -}; - -/////////////////////// -// APPEARANCE TO XML // -/////////////////////// - - -class LLAdvancedAppearanceToXML : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar::dumpArchetypeXML(NULL); - return true; - } -}; - - - -/////////////////////////////// -// TOGGLE CHARACTER GEOMETRY // -/////////////////////////////// - - -class LLAdvancedToggleCharacterGeometry : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_god_request_avatar_geometry(NULL); - return true; -} -}; - - - ///////////////////////////// -// TEST MALE / TEST FEMALE // -///////////////////////////// - -class LLAdvancedTestMale : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_test_male(NULL); - return true; - } -}; - - -class LLAdvancedTestFemale : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_test_female(NULL); - return true; - } -}; - - - -/////////////// -// TOGGLE PG // -/////////////// - - -class LLAdvancedTogglePG : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_toggle_pg(NULL); - return true; - } -}; - - -class LLAdvancedForceParamsToDefault : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLAgent::clearVisualParams(NULL); - return true; - } -}; - - - -////////////////////////// -// RELOAD VERTEX SHADER // -////////////////////////// - - -class LLAdvancedReloadVertexShader : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - reload_vertex_shader(NULL); - return true; - } -}; - - - -//////////////////// -// ANIMATION INFO // -//////////////////// - - -class LLAdvancedToggleAnimationInfo : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar::sShowAnimationDebug = !(LLVOAvatar::sShowAnimationDebug); - return true; - } -}; - -class LLAdvancedCheckAnimationInfo : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLVOAvatar::sShowAnimationDebug; - return new_value; - } -}; - - -////////////////// -// SHOW LOOK AT // -////////////////// - - -class LLAdvancedToggleShowLookAt : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLHUDEffectLookAt::sDebugLookAt = !(LLHUDEffectLookAt::sDebugLookAt); - return true; - } -}; - -class LLAdvancedCheckShowLookAt : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLHUDEffectLookAt::sDebugLookAt; - return new_value; - } -}; - - - -/////////////////// -// SHOW POINT AT // -/////////////////// - - -class LLAdvancedToggleShowPointAt : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLHUDEffectPointAt::sDebugPointAt = !(LLHUDEffectPointAt::sDebugPointAt); - return true; - } -}; - -class LLAdvancedCheckShowPointAt : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLHUDEffectPointAt::sDebugPointAt; - return new_value; - } -}; - - - -///////////////////////// -// DEBUG JOINT UPDATES // -///////////////////////// - - -class LLAdvancedToggleDebugJointUpdates : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar::sJointDebug = !(LLVOAvatar::sJointDebug); - return true; - } -}; - -class LLAdvancedCheckDebugJointUpdates : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLVOAvatar::sJointDebug; - return new_value; - } -}; - - - -///////////////// -// DISABLE LOD // -///////////////// - - -class LLAdvancedToggleDisableLOD : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLViewerJoint::sDisableLOD = !(LLViewerJoint::sDisableLOD); - return true; - } -}; - -class LLAdvancedCheckDisableLOD : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLViewerJoint::sDisableLOD; - return new_value; - } -}; - - - -///////////////////////// -// DEBUG CHARACTER VIS // -///////////////////////// - - -class LLAdvancedToggleDebugCharacterVis : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar::sDebugInvisible = !(LLVOAvatar::sDebugInvisible); - return true; - } -}; - -class LLAdvancedCheckDebugCharacterVis : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLVOAvatar::sDebugInvisible; - return new_value; - } -}; - - -////////////////////// -// DUMP ATTACHMENTS // -////////////////////// - - -class LLAdvancedDumpAttachments : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_dump_attachments(NULL); - return true; - } -}; - - - -///////////////////// -// REBAKE TEXTURES // -///////////////////// - - -class LLAdvancedRebakeTextures : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_rebake_textures(NULL); - return true; - } -}; - - -#if 1 //ndef LL_RELEASE_FOR_DOWNLOAD -/////////////////////////// -// DEBUG AVATAR TEXTURES // -/////////////////////////// - - -class LLAdvancedDebugAvatarTextures : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - if (gAgent.isGodlike()) - { - handle_debug_avatar_textures(NULL); - } - return true; - } -}; - -//////////////////////////////// -// DUMP AVATAR LOCAL TEXTURES // -//////////////////////////////// - - -class LLAdvancedDumpAvatarLocalTextures : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { -#ifndef LL_RELEASE_FOR_DOWNLOAD - handle_dump_avatar_local_textures(NULL); -#endif - return true; - } -}; - -#endif - -///////////////// -// MESSAGE LOG // -///////////////// - - -class LLAdvancedEnableMessageLog : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_viewer_enable_message_log(NULL); - return true; - } -}; - -class LLAdvancedDisableMessageLog : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_viewer_disable_message_log(NULL); - return true; - } -}; - -///////////////// -// DROP PACKET // -///////////////// - - -class LLAdvancedDropPacket : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - gMessageSystem->mPacketRing.dropPackets(1); - return true; - } -}; - - - -///////////////// -// AGENT PILOT // -///////////////// - - -class LLAdvancedAgentPilot : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string command = userdata.asString(); - if ("start playback" == command) - { - LLAgentPilot::startPlayback(NULL); - } - else if ("stop playback" == command) - { - LLAgentPilot::stopPlayback(NULL); - } - else if ("start record" == command) - { - LLAgentPilot::startRecord(NULL); - } - else if ("stop record" == command) - { - LLAgentPilot::saveRecord(NULL); - } - - return true; - } -}; - - - -////////////////////// -// AGENT PILOT LOOP // -////////////////////// - - -class LLAdvancedToggleAgentPilotLoop : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLAgentPilot::sLoop = !(LLAgentPilot::sLoop); - return true; - } -}; - -class LLAdvancedCheckAgentPilotLoop : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLAgentPilot::sLoop; - return new_value; - } -}; - - -///////////////////////// -// SHOW OBJECT UPDATES // -///////////////////////// - - -class LLAdvancedToggleShowObjectUpdates : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - gShowObjectUpdates = !(gShowObjectUpdates); - return true; - } -}; - -class LLAdvancedCheckShowObjectUpdates : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = gShowObjectUpdates; - return new_value; - } -}; - - - -//////////////////// -// COMPRESS IMAGE // -//////////////////// - - -class LLAdvancedCompressImage : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_compress_image(NULL); - return true; - } -}; - - - -///////////////////////// -// SHOW DEBUG SETTINGS // -///////////////////////// - - -class LLAdvancedShowDebugSettings : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLFloaterReg::showInstance("settings_debug",userdata); - return true; - } -}; - - - -//////////////////////// -// VIEW ADMIN OPTIONS // -//////////////////////// - -class LLAdvancedEnableViewAdminOptions : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - // Don't enable in god mode since the admin menu is shown anyway. - // Only enable if the user has set the appropriate debug setting. - bool new_value = !gAgent.getAgentAccess().isGodlikeWithoutAdminMenuFakery() && gSavedSettings.getBOOL("AdminMenu"); - return new_value; - } -}; - -class LLAdvancedToggleViewAdminOptions : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_admin_override_toggle(NULL); - return true; - } -}; - -class LLAdvancedCheckViewAdminOptions : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = check_admin_override(NULL) || gAgent.isGodlike(); - return new_value; - } -}; - -///////////////////////////////////// -// Enable Object Object Occlusion /// -///////////////////////////////////// -class LLAdvancedEnableObjectObjectOcclusion: public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - - bool new_value = gGLManager.mHasOcclusionQuery; // && LLFeatureManager::getInstance()->isFeatureAvailable(userdata.asString()); - return new_value; -} -}; - -///////////////////////////////////// -// Enable Framebuffer Objects /// -///////////////////////////////////// -class LLAdvancedEnableRenderFBO: public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = gGLManager.mHasFramebufferObject; - return new_value; - } -}; - -///////////////////////////////////// -// Enable Deferred Rendering /// -///////////////////////////////////// -class LLAdvancedEnableRenderDeferred: public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = gSavedSettings.getBOOL("RenderUseFBO") && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT > 0) && - LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) > 0; - return new_value; - } -}; - -///////////////////////////////////// -// Enable Deferred Rendering sub-options -///////////////////////////////////// -class LLAdvancedEnableRenderDeferredOptions: public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = gSavedSettings.getBOOL("RenderUseFBO") && gSavedSettings.getBOOL("RenderDeferred"); - return new_value; - } -}; - - - -////////////////// -// ADMIN STATUS // -////////////////// - - -class LLAdvancedRequestAdminStatus : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_god_mode(NULL); - return true; - } -}; - -class LLAdvancedLeaveAdminStatus : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_leave_god_mode(NULL); - return true; - } -}; - -////////////////////////// -// Advanced > Debugging // -////////////////////////// - - -class LLAdvancedForceErrorBreakpoint : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - force_error_breakpoint(NULL); - return true; - } -}; - -class LLAdvancedForceErrorLlerror : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - force_error_llerror(NULL); - return true; - } -}; -class LLAdvancedForceErrorBadMemoryAccess : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - force_error_bad_memory_access(NULL); - return true; - } -}; - -class LLAdvancedForceErrorInfiniteLoop : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - force_error_infinite_loop(NULL); - return true; - } -}; - -class LLAdvancedForceErrorSoftwareException : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - force_error_software_exception(NULL); - return true; - } -}; - -class LLAdvancedForceErrorDriverCrash : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - force_error_driver_crash(NULL); - return true; - } -}; - -class LLAdvancedForceErrorDisconnectViewer : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_disconnect_viewer(NULL); - return true; -} -}; - - -#ifdef TOGGLE_HACKED_GODLIKE_VIEWER - -class LLAdvancedHandleToggleHackedGodmode : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_toggle_hacked_godmode(NULL); - return true; - } -}; - -class LLAdvancedCheckToggleHackedGodmode : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - check_toggle_hacked_godmode(NULL); - return true; - } -}; - -class LLAdvancedEnableToggleHackedGodmode : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = enable_toggle_hacked_godmode(NULL); - return new_value; - } -}; -#endif - - -// -////------------------------------------------------------------------- -//// Advanced menu -////------------------------------------------------------------------- - -////////////////// -// ADMIN MENU // -////////////////// - -// Admin > Object -class LLAdminForceTakeCopy : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - force_take_copy(NULL); - return true; - } -}; - -class LLAdminHandleObjectOwnerSelf : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_object_owner_self(NULL); - return true; - } -}; -class LLAdminHandleObjectOwnerPermissive : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_object_owner_permissive(NULL); - return true; - } -}; - -class LLAdminHandleForceDelete : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_force_delete(NULL); - return true; - } -}; - -class LLAdminHandleObjectLock : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_object_lock(NULL); - return true; - } -}; - -class LLAdminHandleObjectAssetIDs: public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_object_asset_ids(NULL); - return true; - } -}; - -//Admin >Parcel -class LLAdminHandleForceParcelOwnerToMe: public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_force_parcel_owner_to_me(NULL); - return true; - } -}; -class LLAdminHandleForceParcelToContent: public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_force_parcel_to_content(NULL); - return true; - } -}; -class LLAdminHandleClaimPublicLand: public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_claim_public_land(NULL); - return true; - } -}; - -// Admin > Region -class LLAdminHandleRegionDumpTempAssetData: public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_region_dump_temp_asset_data(NULL); - return true; - } -}; -//Admin (Top Level) - -class LLAdminOnSaveState: public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLPanelRegionTools::onSaveState(NULL); - return true; -} -}; - - -//----------------------------------------------------------------------------- -// cleanup_menus() -//----------------------------------------------------------------------------- -void cleanup_menus() -{ - delete gMenuParcelObserver; - gMenuParcelObserver = NULL; - - delete gMenuAvatarSelf; - gMenuAvatarSelf = NULL; - - delete gMenuAvatarOther; - gMenuAvatarOther = NULL; - - delete gMenuObject; - gMenuObject = NULL; - - delete gMenuAttachmentSelf; - gMenuAttachmentSelf = NULL; - - delete gMenuAttachmentOther; - gMenuAttachmentSelf = NULL; - - delete gMenuLand; - gMenuLand = NULL; - - delete gMenuBarView; - gMenuBarView = NULL; - - delete gPopupMenuView; - gPopupMenuView = NULL; - - delete gMenuHolder; - gMenuHolder = NULL; -} - -//----------------------------------------------------------------------------- -// Object pie menu -//----------------------------------------------------------------------------- - -class LLObjectReportAbuse : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (objectp) - { - LLFloaterReporter::showFromObject(objectp->getID()); - } - return true; - } -}; - -// Enabled it you clicked an object -class LLObjectEnableReportAbuse : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLSelectMgr::getInstance()->getSelection()->getObjectCount() != 0; - return new_value; - } -}; - -void handle_object_touch() -{ - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) return; - - LLPickInfo pick = LLToolPie::getInstance()->getPick(); - - LLMessageSystem *msg = gMessageSystem; - - msg->newMessageFast(_PREHASH_ObjectGrab); - msg->nextBlockFast( _PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast( _PREHASH_ObjectData); - msg->addU32Fast( _PREHASH_LocalID, object->mLocalID); - msg->addVector3Fast(_PREHASH_GrabOffset, LLVector3::zero ); - msg->nextBlock("SurfaceInfo"); - msg->addVector3("UVCoord", LLVector3(pick.mUVCoords)); - msg->addVector3("STCoord", LLVector3(pick.mSTCoords)); - msg->addS32Fast(_PREHASH_FaceIndex, pick.mObjectFace); - msg->addVector3("Position", pick.mIntersection); - msg->addVector3("Normal", pick.mNormal); - msg->addVector3("Binormal", pick.mBinormal); - msg->sendMessage( object->getRegion()->getHost()); - - // *NOTE: Hope the packets arrive safely and in order or else - // there will be some problems. - // *TODO: Just fix this bad assumption. - msg->newMessageFast(_PREHASH_ObjectDeGrab); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_ObjectData); - msg->addU32Fast(_PREHASH_LocalID, object->mLocalID); - msg->nextBlock("SurfaceInfo"); - msg->addVector3("UVCoord", LLVector3(pick.mUVCoords)); - msg->addVector3("STCoord", LLVector3(pick.mSTCoords)); - msg->addS32Fast(_PREHASH_FaceIndex, pick.mObjectFace); - msg->addVector3("Position", pick.mIntersection); - msg->addVector3("Normal", pick.mNormal); - msg->addVector3("Binormal", pick.mBinormal); - msg->sendMessage(object->getRegion()->getHost()); -} - -static void init_default_item_label(const std::string& item_name) -{ - boost::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name); - if (it == sDefaultItemLabels.end()) - { - // *NOTE: This will not work for items of type LLMenuItemCheckGL because they return boolean value - // (doesn't seem to matter much ATM). - LLStringExplicit default_label = gMenuHolder->childGetValue(item_name).asString(); - if (!default_label.empty()) - { - sDefaultItemLabels.insert(std::pair<std::string, LLStringExplicit>(item_name, default_label)); - } - } -} - -static LLStringExplicit get_default_item_label(const std::string& item_name) -{ - LLStringExplicit res(""); - boost::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name); - if (it != sDefaultItemLabels.end()) - { - res = it->second; - } - - return res; -} - - -bool enable_object_touch(LLUICtrl* ctrl) -{ - LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - - bool new_value = obj && obj->flagHandleTouch(); - - std::string item_name = ctrl->getName(); - init_default_item_label(item_name); - - // Update label based on the node touch name if available. - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if (node && node->mValid && !node->mTouchName.empty()) - { - gMenuHolder->childSetText(item_name, node->mTouchName); - } - else - { - gMenuHolder->childSetText(item_name, get_default_item_label(item_name)); - } - - return new_value; -}; - -//void label_touch(std::string& label, void*) -//{ -// LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); -// if (node && node->mValid && !node->mTouchName.empty()) -// { -// label.assign(node->mTouchName); -// } -// else -// { -// label.assign("Touch"); -// } -//} - -void handle_object_open() -{ - LLFloaterReg::showInstance("openobject"); -} - -bool enable_object_open() -{ - // Look for contents in root object, which is all the LLFloaterOpenObject - // understands. - LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!obj) return false; - - LLViewerObject* root = obj->getRootEdit(); - if (!root) return false; - - return root->allowOpen(); -} - - -class LLViewJoystickFlycam : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_toggle_flycam(); - return true; - } -}; - -class LLViewCheckJoystickFlycam : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLViewerJoystick::getInstance()->getOverrideCamera(); - return new_value; - } -}; - -void handle_toggle_flycam() -{ - LLViewerJoystick::getInstance()->toggleFlycam(); -} - -class LLObjectBuild : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") ) - { - // zoom in if we're looking at the avatar - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); - gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); - gAgentCamera.cameraZoomIn(0.666f); - gAgentCamera.cameraOrbitOver( 30.f * DEG_TO_RAD ); - gViewerWindow->moveCursorToCenter(); - } - else if ( gSavedSettings.getBOOL("EditCameraMovement") ) - { - gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); - gViewerWindow->moveCursorToCenter(); - } - - LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); - LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompCreate::getInstance() ); - - // Could be first use - //LLFirstUse::useBuild(); - return true; - } -}; - - -void handle_object_edit() -{ - LLViewerParcelMgr::getInstance()->deselectLand(); - - if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit()) - { - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - - if (selection->getSelectType() == SELECT_TYPE_HUD || !gSavedSettings.getBOOL("EditCameraMovement")) - { - // always freeze camera in space, even if camera doesn't move - // so, for example, follow cam scripts can't affect you when in build mode - gAgentCamera.setFocusGlobal(gAgentCamera.calcFocusPositionTargetGlobal(), LLUUID::null); - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); - } - else - { - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); - LLViewerObject* selected_objectp = selection->getFirstRootObject(); - if (selected_objectp) - { - // zoom in on object center instead of where we clicked, as we need to see the manipulator handles - gAgentCamera.setFocusGlobal(selected_objectp->getPositionGlobal(), selected_objectp->getID()); - gAgentCamera.cameraZoomIn(0.666f); - gAgentCamera.cameraOrbitOver( 30.f * DEG_TO_RAD ); - gViewerWindow->moveCursorToCenter(); - } - } - } - - LLFloaterReg::showInstance("build"); - - LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); - gFloaterTools->setEditTool( LLToolCompTranslate::getInstance() ); - - LLViewerJoystick::getInstance()->moveObjects(true); - LLViewerJoystick::getInstance()->setNeedsReset(true); - - // Could be first use - //LLFirstUse::useBuild(); - return; -} - -void handle_object_inspect() -{ - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - LLViewerObject* selected_objectp = selection->getFirstRootObject(); - if (selected_objectp) - { - LLSD key; - key["task"] = "task"; - LLSideTray::getInstance()->showPanel("sidepanel_inventory", key); - } - - /* - // Old floater properties - LLFloaterReg::showInstance("inspect", LLSD()); - */ -} - -//--------------------------------------------------------------------------- -// Land pie menu -//--------------------------------------------------------------------------- -class LLLandBuild : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLViewerParcelMgr::getInstance()->deselectLand(); - - if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") ) - { - // zoom in if we're looking at the avatar - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); - gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); - gAgentCamera.cameraZoomIn(0.666f); - gAgentCamera.cameraOrbitOver( 30.f * DEG_TO_RAD ); - gViewerWindow->moveCursorToCenter(); - } - else if ( gSavedSettings.getBOOL("EditCameraMovement") ) - { - // otherwise just move focus - gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); - gViewerWindow->moveCursorToCenter(); - } - - - LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); - LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompCreate::getInstance() ); - - // Could be first use - //LLFirstUse::useBuild(); - return true; - } -}; - -class LLLandBuyPass : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLPanelLandGeneral::onClickBuyPass((void *)FALSE); - return true; - } -}; - -class LLLandEnableBuyPass : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLPanelLandGeneral::enableBuyPass(NULL); - return new_value; - } -}; - -// BUG: Should really check if CLICK POINT is in a parcel where you can build. -BOOL enable_land_build(void*) -{ - if (gAgent.isGodlike()) return TRUE; - if (gAgent.inPrelude()) return FALSE; - - BOOL can_build = FALSE; - LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if (agent_parcel) - { - can_build = agent_parcel->getAllowModify(); - } - return can_build; -} - -// BUG: Should really check if OBJECT is in a parcel where you can build. -BOOL enable_object_build(void*) -{ - if (gAgent.isGodlike()) return TRUE; - if (gAgent.inPrelude()) return FALSE; - - BOOL can_build = FALSE; - LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if (agent_parcel) - { - can_build = agent_parcel->getAllowModify(); - } - return can_build; -} - -bool enable_object_edit() -{ - // *HACK: The new "prelude" Help Islands have a build sandbox area, - // so users need the Edit and Create pie menu options when they are - // there. Eventually this needs to be replaced with code that only - // lets you edit objects if you have permission to do so (edit perms, - // group edit, god). See also lltoolbar.cpp. JC - bool enable = false; - if (gAgent.inPrelude()) - { - enable = LLViewerParcelMgr::getInstance()->allowAgentBuild() - || LLSelectMgr::getInstance()->getSelection()->isAttachment(); - } - else if (LLSelectMgr::getInstance()->selectGetAllValidAndObjectsFound()) - { - enable = true; - } - - return enable; -} - -// mutually exclusive - show either edit option or build in menu -bool enable_object_build() -{ - return !enable_object_edit(); -} - -class LLSelfRemoveAllAttachments : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLAgentWearables::userRemoveAllAttachments(); - return true; - } -}; - -class LLSelfEnableRemoveAllAttachments : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = false; - if (isAgentAvatarValid()) - { - for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); - iter != gAgentAvatarp->mAttachmentPoints.end(); ) - { - LLVOAvatar::attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - if (attachment->getNumObjects() > 0) - { - new_value = true; - break; - } - } - } - return new_value; - } -}; - -BOOL enable_has_attachments(void*) -{ - - return FALSE; -} - -//--------------------------------------------------------------------------- -// Avatar pie menu -//--------------------------------------------------------------------------- -//void handle_follow(void *userdata) -//{ -// // follow a given avatar by ID -// LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); -// if (objectp) -// { -// gAgent.startFollowPilot(objectp->getID()); -// } -//} - -bool enable_object_mute() -{ - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) return false; - - LLVOAvatar* avatar = find_avatar_from_object(object); - if (avatar) - { - // It's an avatar - LLNameValue *lastname = avatar->getNVPair("LastName"); - bool is_linden = - lastname && !LLStringUtil::compareStrings(lastname->getString(), "Linden"); - bool is_self = avatar->isSelf(); - return !is_linden && !is_self; - } - else - { - // Just a regular object - return LLSelectMgr::getInstance()->getSelection()-> - contains( object, SELECT_ALL_TES ); - } -} - -class LLObjectMute : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) return true; - - LLUUID id; - std::string name; - LLMute::EType type; - LLVOAvatar* avatar = find_avatar_from_object(object); - if (avatar) - { - id = avatar->getID(); - - LLNameValue *firstname = avatar->getNVPair("FirstName"); - LLNameValue *lastname = avatar->getNVPair("LastName"); - if (firstname && lastname) - { - name = LLCacheName::buildFullName( - firstname->getString(), lastname->getString()); - } - - type = LLMute::AGENT; - } - else - { - // it's an object - id = object->getID(); - - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if (node) - { - name = node->mName; - } - - type = LLMute::OBJECT; - } - - LLMute mute(id, name, type); - if (LLMuteList::getInstance()->isMuted(mute.mID)) - { - LLMuteList::getInstance()->remove(mute); - } - else - { - LLMuteList::getInstance()->add(mute); - LLPanelBlockedList::showPanelAndSelect(mute.mID); - } - - return true; - } -}; - -bool handle_go_to() -{ - // try simulator autopilot - std::vector<std::string> strings; - std::string val; - LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal; - val = llformat("%g", pos.mdV[VX]); - strings.push_back(val); - val = llformat("%g", pos.mdV[VY]); - strings.push_back(val); - val = llformat("%g", pos.mdV[VZ]); - strings.push_back(val); - send_generic_message("autopilot", strings); - - LLViewerParcelMgr::getInstance()->deselectLand(); - - if (isAgentAvatarValid() && !gSavedSettings.getBOOL("AutoPilotLocksCamera")) - { - gAgentCamera.setFocusGlobal(gAgentCamera.getFocusTargetGlobal(), gAgentAvatarp->getID()); - } - else - { - // Snap camera back to behind avatar - gAgentCamera.setFocusOnAvatar(TRUE, ANIMATE); - } - - // Could be first use - //LLFirstUse::useGoTo(); - return true; -} - -class LLGoToObject : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - return handle_go_to(); - } -}; - -class LLAvatarReportAbuse : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - LLFloaterReporter::showFromObject(avatar->getID()); - } - return true; - } -}; - - -//--------------------------------------------------------------------------- -// Parcel freeze, eject, etc. -//--------------------------------------------------------------------------- -bool callback_freeze(const LLSD& notification, const LLSD& response) -{ - LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - if (0 == option || 1 == option) - { - U32 flags = 0x0; - if (1 == option) - { - // unfreeze - flags |= 0x1; - } - - LLMessageSystem* msg = gMessageSystem; - LLViewerObject* avatar = gObjectList.findObject(avatar_id); - - if (avatar) - { - msg->newMessage("FreezeUser"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("Data"); - msg->addUUID("TargetID", avatar_id ); - msg->addU32("Flags", flags ); - msg->sendReliable( avatar->getRegion()->getHost() ); - } - } - return false; -} - - -void handle_avatar_freeze(const LLSD& avatar_id) -{ - // Use avatar_id if available, otherwise default to right-click avatar - LLVOAvatar* avatar = NULL; - if (avatar_id.asUUID().notNull()) - { - avatar = find_avatar_from_object(avatar_id.asUUID()); - } - else - { - avatar = find_avatar_from_object( - LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - } - - if( avatar ) - { - std::string fullname = avatar->getFullname(); - LLSD payload; - payload["avatar_id"] = avatar->getID(); - - if (!fullname.empty()) - { - LLSD args; - args["AVATAR_NAME"] = fullname; - LLNotificationsUtil::add("FreezeAvatarFullname", - args, - payload, - callback_freeze); - } - else - { - LLNotificationsUtil::add("FreezeAvatar", - LLSD(), - payload, - callback_freeze); - } - } -} - -class LLAvatarVisibleDebug : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - return gAgent.isGodlike(); - } -}; - -class LLAvatarDebug : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if( avatar ) - { - if (avatar->isSelf()) - { - ((LLVOAvatarSelf *)avatar)->dumpLocalTextures(); - } - llinfos << "Dumping temporary asset data to simulator logs for avatar " << avatar->getID() << llendl; - std::vector<std::string> strings; - strings.push_back(avatar->getID().asString()); - LLUUID invoice; - send_generic_message("dumptempassetdata", strings, invoice); - LLFloaterReg::showInstance( "avatar_textures", LLSD(avatar->getID()) ); - } - return true; - } -}; - -bool callback_eject(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (2 == option) - { - // Cancel button. - return false; - } - LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); - bool ban_enabled = notification["payload"]["ban_enabled"].asBoolean(); - - if (0 == option) - { - // Eject button - LLMessageSystem* msg = gMessageSystem; - LLViewerObject* avatar = gObjectList.findObject(avatar_id); - - if (avatar) - { - U32 flags = 0x0; - msg->newMessage("EjectUser"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID() ); - msg->addUUID("SessionID", gAgent.getSessionID() ); - msg->nextBlock("Data"); - msg->addUUID("TargetID", avatar_id ); - msg->addU32("Flags", flags ); - msg->sendReliable( avatar->getRegion()->getHost() ); - } - } - else if (ban_enabled) - { - // This is tricky. It is similar to say if it is not an 'Eject' button, - // and it is also not an 'Cancle' button, and ban_enabled==ture, - // it should be the 'Eject and Ban' button. - LLMessageSystem* msg = gMessageSystem; - LLViewerObject* avatar = gObjectList.findObject(avatar_id); - - if (avatar) - { - U32 flags = 0x1; - msg->newMessage("EjectUser"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID() ); - msg->addUUID("SessionID", gAgent.getSessionID() ); - msg->nextBlock("Data"); - msg->addUUID("TargetID", avatar_id ); - msg->addU32("Flags", flags ); - msg->sendReliable( avatar->getRegion()->getHost() ); - } - } - return false; -} - -void handle_avatar_eject(const LLSD& avatar_id) -{ - // Use avatar_id if available, otherwise default to right-click avatar - LLVOAvatar* avatar = NULL; - if (avatar_id.asUUID().notNull()) - { - avatar = find_avatar_from_object(avatar_id.asUUID()); - } - else - { - avatar = find_avatar_from_object( - LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - } - - if( avatar ) - { - LLSD payload; - payload["avatar_id"] = avatar->getID(); - std::string fullname = avatar->getFullname(); - - const LLVector3d& pos = avatar->getPositionGlobal(); - LLParcel* parcel = LLViewerParcelMgr::getInstance()->selectParcelAt(pos)->getParcel(); - - if (LLViewerParcelMgr::getInstance()->isParcelOwnedByAgent(parcel,GP_LAND_MANAGE_BANNED)) - { - payload["ban_enabled"] = true; - if (!fullname.empty()) - { - LLSD args; - args["AVATAR_NAME"] = fullname; - LLNotificationsUtil::add("EjectAvatarFullname", - args, - payload, - callback_eject); - } - else - { - LLNotificationsUtil::add("EjectAvatarFullname", - LLSD(), - payload, - callback_eject); - } - } - else - { - payload["ban_enabled"] = false; - if (!fullname.empty()) - { - LLSD args; - args["AVATAR_NAME"] = fullname; - LLNotificationsUtil::add("EjectAvatarFullnameNoBan", - args, - payload, - callback_eject); - } - else - { - LLNotificationsUtil::add("EjectAvatarNoBan", - LLSD(), - payload, - callback_eject); - } - } - } -} - -bool enable_freeze_eject(const LLSD& avatar_id) -{ - // Use avatar_id if available, otherwise default to right-click avatar - LLVOAvatar* avatar = NULL; - if (avatar_id.asUUID().notNull()) - { - avatar = find_avatar_from_object(avatar_id.asUUID()); - } - else - { - avatar = find_avatar_from_object( - LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - } - if (!avatar) return false; - - // Gods can always freeze - if (gAgent.isGodlike()) return true; - - // Estate owners / managers can freeze - // Parcel owners can also freeze - const LLVector3& pos = avatar->getPositionRegion(); - const LLVector3d& pos_global = avatar->getPositionGlobal(); - LLParcel* parcel = LLViewerParcelMgr::getInstance()->selectParcelAt(pos_global)->getParcel(); - LLViewerRegion* region = avatar->getRegion(); - if (!region) return false; - - bool new_value = region->isOwnedSelf(pos); - if (!new_value || region->isOwnedGroup(pos)) - { - new_value = LLViewerParcelMgr::getInstance()->isParcelOwnedByAgent(parcel,GP_LAND_ADMIN); - } - return new_value; -} - - -void login_done(S32 which, void *user) -{ - llinfos << "Login done " << which << llendl; - - LLPanelLogin::closePanel(); -} - - -bool callback_leave_group(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0) - { - LLMessageSystem *msg = gMessageSystem; - - msg->newMessageFast(_PREHASH_LeaveGroupRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_GroupData); - msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID() ); - gAgent.sendReliableMessage(); - } - return false; -} - -void append_aggregate(std::string& string, const LLAggregatePermissions& ag_perm, PermissionBit bit, const char* txt) -{ - LLAggregatePermissions::EValue val = ag_perm.getValue(bit); - std::string buffer; - switch(val) - { - case LLAggregatePermissions::AP_NONE: - buffer = llformat( "* %s None\n", txt); - break; - case LLAggregatePermissions::AP_SOME: - buffer = llformat( "* %s Some\n", txt); - break; - case LLAggregatePermissions::AP_ALL: - buffer = llformat( "* %s All\n", txt); - break; - case LLAggregatePermissions::AP_EMPTY: - default: - break; - } - string.append(buffer); -} - -bool enable_buy_object() -{ - // In order to buy, there must only be 1 purchaseable object in - // the selection manger. - if(LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() != 1) return false; - LLViewerObject* obj = NULL; - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if(node) - { - obj = node->getObject(); - if(!obj) return false; - - if( for_sale_selection(node) ) - { - // *NOTE: Is this needed? This checks to see if anyone owns the - // object, dating back to when we had "public" objects owned by - // no one. JC - if(obj->permAnyOwner()) return true; - } - } - return false; -} - -// Note: This will only work if the selected object's data has been -// received by the viewer and cached in the selection manager. -void handle_buy_object(LLSaleInfo sale_info) -{ - if(!LLSelectMgr::getInstance()->selectGetAllRootsValid()) - { - LLNotificationsUtil::add("UnableToBuyWhileDownloading"); - return; - } - - LLUUID owner_id; - std::string owner_name; - BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name); - if (!owners_identical) - { - LLNotificationsUtil::add("CannotBuyObjectsFromDifferentOwners"); - return; - } - - LLPermissions perm; - BOOL valid = LLSelectMgr::getInstance()->selectGetPermissions(perm); - LLAggregatePermissions ag_perm; - valid &= LLSelectMgr::getInstance()->selectGetAggregatePermissions(ag_perm); - if(!valid || !sale_info.isForSale() || !perm.allowTransferTo(gAgent.getID())) - { - LLNotificationsUtil::add("ObjectNotForSale"); - return; - } - - LLFloaterBuy::show(sale_info); -} - - -void handle_buy_contents(LLSaleInfo sale_info) -{ - LLFloaterBuyContents::show(sale_info); -} - -void handle_region_dump_temp_asset_data(void*) -{ - llinfos << "Dumping temporary asset data to simulator logs" << llendl; - std::vector<std::string> strings; - LLUUID invoice; - send_generic_message("dumptempassetdata", strings, invoice); -} - -void handle_region_clear_temp_asset_data(void*) -{ - llinfos << "Clearing temporary asset data" << llendl; - std::vector<std::string> strings; - LLUUID invoice; - send_generic_message("cleartempassetdata", strings, invoice); -} - -void handle_region_dump_settings(void*) -{ - LLViewerRegion* regionp = gAgent.getRegion(); - if (regionp) - { - llinfos << "Damage: " << (regionp->getAllowDamage() ? "on" : "off") << llendl; - llinfos << "Landmark: " << (regionp->getAllowLandmark() ? "on" : "off") << llendl; - llinfos << "SetHome: " << (regionp->getAllowSetHome() ? "on" : "off") << llendl; - llinfos << "ResetHome: " << (regionp->getResetHomeOnTeleport() ? "on" : "off") << llendl; - llinfos << "SunFixed: " << (regionp->getSunFixed() ? "on" : "off") << llendl; - llinfos << "BlockFly: " << (regionp->getBlockFly() ? "on" : "off") << llendl; - llinfos << "AllowP2P: " << (regionp->getAllowDirectTeleport() ? "on" : "off") << llendl; - llinfos << "Water: " << (regionp->getWaterHeight()) << llendl; - } -} - -void handle_dump_group_info(void *) -{ - gAgent.dumpGroupInfo(); -} - -void handle_dump_capabilities_info(void *) -{ - LLViewerRegion* regionp = gAgent.getRegion(); - if (regionp) - { - regionp->logActiveCapabilities(); - } -} - -void handle_dump_region_object_cache(void*) -{ - LLViewerRegion* regionp = gAgent.getRegion(); - if (regionp) - { - regionp->dumpCache(); - } -} - -void handle_dump_focus() -{ - LLUICtrl *ctrl = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); - - llinfos << "Keyboard focus " << (ctrl ? ctrl->getName() : "(none)") << llendl; -} - -class LLSelfStandUp : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - gAgent.standUp(); - return true; - } -}; - -bool enable_standup_self() -{ - return isAgentAvatarValid() && gAgentAvatarp->isSitting(); -} - -class LLSelfSitDown : public view_listener_t - { - bool handleEvent(const LLSD& userdata) - { - gAgent.sitDown(); - return true; - } - }; - -bool enable_sitdown_self() -{ - return isAgentAvatarValid() && !gAgentAvatarp->isSitting() && !gAgent.getFlying(); -} - -// Used from the login screen to aid in UI work on side tray -void handle_show_side_tray() -{ - LLSideTray* side_tray = LLSideTray::getInstance(); - LLView* root = gViewerWindow->getRootView(); - // automatically removes and re-adds if there already - root->addChild(side_tray); -} - -// Toggle one of "People" panel tabs in side tray. -class LLTogglePanelPeopleTab : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string panel_name = userdata.asString(); - - LLSD param; - param["people_panel_tab_name"] = panel_name; - - static LLPanel* friends_panel = NULL; - static LLPanel* groups_panel = NULL; - static LLPanel* nearby_panel = NULL; - - if (panel_name == "friends_panel") - { - return togglePeoplePanel(friends_panel, panel_name, param); - } - else if (panel_name == "groups_panel") - { - return togglePeoplePanel(groups_panel, panel_name, param); - } - else if (panel_name == "nearby_panel") - { - return togglePeoplePanel(nearby_panel, panel_name, param); - } - else - { - return false; - } - } - - static bool togglePeoplePanel(LLPanel* &panel, const std::string& panel_name, const LLSD& param) - { - if(!panel) - { - panel = LLSideTray::getInstance()->getPanel(panel_name); - if(!panel) - return false; - } - - LLSideTray::getInstance()->togglePanel(panel, "panel_people", param); - - return true; - } -}; - -BOOL check_admin_override(void*) -{ - return gAgent.getAdminOverride(); -} - -void handle_admin_override_toggle(void*) -{ - gAgent.setAdminOverride(!gAgent.getAdminOverride()); - - // The above may have affected which debug menus are visible - show_debug_menus(); -} - -void handle_god_mode(void*) -{ - gAgent.requestEnterGodMode(); -} - -void handle_leave_god_mode(void*) -{ - gAgent.requestLeaveGodMode(); -} - -void set_god_level(U8 god_level) -{ - U8 old_god_level = gAgent.getGodLevel(); - gAgent.setGodLevel( god_level ); - LLViewerParcelMgr::getInstance()->notifyObservers(); - - // God mode changes region visibility - LLWorldMap::getInstance()->reloadItems(true); - - // inventory in items may change in god mode - gObjectList.dirtyAllObjectInventory(); - - if(gViewerWindow) - { - gViewerWindow->setMenuBackgroundColor(god_level > GOD_NOT, - LLGridManager::getInstance()->isInProductionGrid()); - } - - LLSD args; - if(god_level > GOD_NOT) - { - args["LEVEL"] = llformat("%d",(S32)god_level); - LLNotificationsUtil::add("EnteringGodMode", args); - } - else - { - args["LEVEL"] = llformat("%d",(S32)old_god_level); - LLNotificationsUtil::add("LeavingGodMode", args); - } - - // changing god-level can affect which menus we see - show_debug_menus(); - - // changing god-level can invalidate search results - LLFloaterSearch *search = dynamic_cast<LLFloaterSearch*>(LLFloaterReg::getInstance("search")); - if (search) - { - search->godLevelChanged(god_level); - } -} - -#ifdef TOGGLE_HACKED_GODLIKE_VIEWER -void handle_toggle_hacked_godmode(void*) -{ - gHackGodmode = !gHackGodmode; - set_god_level(gHackGodmode ? GOD_MAINTENANCE : GOD_NOT); -} - -BOOL check_toggle_hacked_godmode(void*) -{ - return gHackGodmode; -} - -bool enable_toggle_hacked_godmode(void*) -{ - return !LLGridManager::getInstance()->isInProductionGrid(); -} -#endif - -void process_grant_godlike_powers(LLMessageSystem* msg, void**) -{ - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - LLUUID session_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); - if((agent_id == gAgent.getID()) && (session_id == gAgent.getSessionID())) - { - U8 god_level; - msg->getU8Fast(_PREHASH_GrantData, _PREHASH_GodLevel, god_level); - set_god_level(god_level); - } - else - { - llwarns << "Grant godlike for wrong agent " << agent_id << llendl; - } -} - -/* -class LLHaveCallingcard : public LLInventoryCollectFunctor -{ -public: - LLHaveCallingcard(const LLUUID& agent_id); - virtual ~LLHaveCallingcard() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); - BOOL isThere() const { return mIsThere;} -protected: - LLUUID mID; - BOOL mIsThere; -}; - -LLHaveCallingcard::LLHaveCallingcard(const LLUUID& agent_id) : - mID(agent_id), - mIsThere(FALSE) -{ -} - -bool LLHaveCallingcard::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) -{ - if(item) - { - if((item->getType() == LLAssetType::AT_CALLINGCARD) - && (item->getCreatorUUID() == mID)) - { - mIsThere = TRUE; - } - } - return FALSE; -} -*/ - -BOOL is_agent_mappable(const LLUUID& agent_id) -{ - const LLRelationship* buddy_info = NULL; - bool is_friend = LLAvatarActions::isFriend(agent_id); - - if (is_friend) - buddy_info = LLAvatarTracker::instance().getBuddyInfo(agent_id); - - return (buddy_info && - buddy_info->isOnline() && - buddy_info->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION) - ); -} - - -// Enable a menu item when you don't have someone's card. -class LLAvatarEnableAddFriend : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID()); - return new_value; - } -}; - -void request_friendship(const LLUUID& dest_id) -{ - LLViewerObject* dest = gObjectList.findObject(dest_id); - if(dest && dest->isAvatar()) - { - std::string full_name; - LLNameValue* nvfirst = dest->getNVPair("FirstName"); - LLNameValue* nvlast = dest->getNVPair("LastName"); - if(nvfirst && nvlast) - { - full_name = LLCacheName::buildFullName( - nvfirst->getString(), nvlast->getString()); - } - if (!full_name.empty()) - { - LLAvatarActions::requestFriendshipDialog(dest_id, full_name); - } - else - { - LLNotificationsUtil::add("CantOfferFriendship"); - } - } -} - - -class LLEditEnableCustomizeAvatar : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = gAgentWearables.areWearablesLoaded(); - return new_value; - } -}; - -class LLEnableEditShape : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - return gAgentWearables.isWearableModifiable(LLWearableType::WT_SHAPE, 0); - } -}; - -bool is_object_sittable() -{ - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - - if (object && object->getPCode() == LL_PCODE_VOLUME) - { - return true; - } - else - { - return false; - } -} - - -// only works on pie menu -void handle_object_sit_or_stand() -{ - LLPickInfo pick = LLToolPie::getInstance()->getPick(); - LLViewerObject *object = pick.getObject();; - if (!object || pick.mPickType == LLPickInfo::PICK_FLORA) - { - return; - } - - if (sitting_on_selection()) - { - gAgent.standUp(); - return; - } - - // get object selection offset - - if (object && object->getPCode() == LL_PCODE_VOLUME) - { - - gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gMessageSystem->nextBlockFast(_PREHASH_TargetObject); - gMessageSystem->addUUIDFast(_PREHASH_TargetID, object->mID); - gMessageSystem->addVector3Fast(_PREHASH_Offset, pick.mObjectOffset); - - object->getRegion()->sendReliableMessage(); - } -} - -void near_sit_down_point(BOOL success, void *) -{ - if (success) - { - gAgent.setFlying(FALSE); - gAgent.setControlFlags(AGENT_CONTROL_SIT_ON_GROUND); - - // Might be first sit - //LLFirstUse::useSit(); - } -} - -class LLLandSit : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - gAgent.standUp(); - LLViewerParcelMgr::getInstance()->deselectLand(); - - LLVector3d posGlobal = LLToolPie::getInstance()->getPick().mPosGlobal; - - LLQuaternion target_rot; - if (isAgentAvatarValid()) - { - target_rot = gAgentAvatarp->getRotation(); - } - else - { - target_rot = gAgent.getFrameAgent().getQuaternion(); - } - gAgent.startAutoPilotGlobal(posGlobal, "Sit", &target_rot, near_sit_down_point, NULL, 0.7f); - return true; - } -}; - -//------------------------------------------------------------------- -// Help menu functions -//------------------------------------------------------------------- - -// -// Major mode switching -// -void reset_view_final( BOOL proceed ); - -void handle_reset_view() -{ - if (gAgentCamera.cameraCustomizeAvatar()) - { - // switching to outfit selector should automagically save any currently edited wearable - LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "my_outfits")); - } - - gAgentCamera.switchCameraPreset(CAMERA_PRESET_REAR_VIEW); - reset_view_final( TRUE ); - LLFloaterCamera::resetCameraMode(); -} - -class LLViewResetView : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - handle_reset_view(); - return true; - } -}; - -// Note: extra parameters allow this function to be called from dialog. -void reset_view_final( BOOL proceed ) -{ - if( !proceed ) - { - return; - } - - gAgentCamera.resetView(TRUE, TRUE); - gAgentCamera.setLookAt(LOOKAT_TARGET_CLEAR); -} - -class LLViewLookAtLastChatter : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - gAgentCamera.lookAtLastChat(); - return true; - } -}; - -class LLViewMouselook : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - if (!gAgentCamera.cameraMouselook()) - { - gAgentCamera.changeCameraToMouselook(); - } - else - { - gAgentCamera.changeCameraToDefault(); - } - return true; - } -}; - -class LLViewDefaultUISize : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - gSavedSettings.setF32("UIScaleFactor", 1.0f); - gSavedSettings.setBOOL("UIAutoScale", FALSE); - gViewerWindow->reshape(gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw()); - return true; - } -}; - -class LLEditDuplicate : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - if(LLEditMenuHandler::gEditMenuHandler) - { - LLEditMenuHandler::gEditMenuHandler->duplicate(); - } - return true; - } -}; - -class LLEditEnableDuplicate : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDuplicate(); - return new_value; - } -}; - -void handle_duplicate_in_place(void*) -{ - llinfos << "handle_duplicate_in_place" << llendl; - - LLVector3 offset(0.f, 0.f, 0.f); - LLSelectMgr::getInstance()->selectDuplicate(offset, TRUE); -} - -/* dead code 30-apr-2008 -void handle_deed_object_to_group(void*) -{ - LLUUID group_id; - - LLSelectMgr::getInstance()->selectGetGroup(group_id); - LLSelectMgr::getInstance()->sendOwner(LLUUID::null, group_id, FALSE); - LLViewerStats::getInstance()->incStat(LLViewerStats::ST_RELEASE_COUNT); -} - -BOOL enable_deed_object_to_group(void*) -{ - if(LLSelectMgr::getInstance()->getSelection()->isEmpty()) return FALSE; - LLPermissions perm; - LLUUID group_id; - - if (LLSelectMgr::getInstance()->selectGetGroup(group_id) && - gAgent.hasPowerInGroup(group_id, GP_OBJECT_DEED) && - LLSelectMgr::getInstance()->selectGetPermissions(perm) && - perm.deedToGroup(gAgent.getID(), group_id)) - { - return TRUE; - } - return FALSE; -} - -*/ - - -/* - * No longer able to support viewer side manipulations in this way - * -void god_force_inv_owner_permissive(LLViewerObject* object, - LLInventoryObject::object_list_t* inventory, - S32 serial_num, - void*) -{ - typedef std::vector<LLPointer<LLViewerInventoryItem> > item_array_t; - item_array_t items; - - LLInventoryObject::object_list_t::const_iterator inv_it = inventory->begin(); - LLInventoryObject::object_list_t::const_iterator inv_end = inventory->end(); - for ( ; inv_it != inv_end; ++inv_it) - { - if(((*inv_it)->getType() != LLAssetType::AT_CATEGORY)) - { - LLInventoryObject* obj = *inv_it; - LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem((LLViewerInventoryItem*)obj); - LLPermissions perm(new_item->getPermissions()); - perm.setMaskBase(PERM_ALL); - perm.setMaskOwner(PERM_ALL); - new_item->setPermissions(perm); - items.push_back(new_item); - } - } - item_array_t::iterator end = items.end(); - item_array_t::iterator it; - for(it = items.begin(); it != end; ++it) - { - // since we have the inventory item in the callback, it should not - // invalidate iteration through the selection manager. - object->updateInventory((*it), TASK_INVENTORY_ITEM_KEY, false); - } -} -*/ - -void handle_object_owner_permissive(void*) -{ - // only send this if they're a god. - if(gAgent.isGodlike()) - { - // do the objects. - LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_BASE, TRUE, PERM_ALL, TRUE); - LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, TRUE, PERM_ALL, TRUE); - } -} - -void handle_object_owner_self(void*) -{ - // only send this if they're a god. - if(gAgent.isGodlike()) - { - LLSelectMgr::getInstance()->sendOwner(gAgent.getID(), gAgent.getGroupID(), TRUE); - } -} - -// Shortcut to set owner permissions to not editable. -void handle_object_lock(void*) -{ - LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, FALSE, PERM_MODIFY); -} - -void handle_object_asset_ids(void*) -{ - // only send this if they're a god. - if (gAgent.isGodlike()) - { - LLSelectMgr::getInstance()->sendGodlikeRequest("objectinfo", "assetids"); - } -} - -void handle_force_parcel_owner_to_me(void*) -{ - LLViewerParcelMgr::getInstance()->sendParcelGodForceOwner( gAgent.getID() ); -} - -void handle_force_parcel_to_content(void*) -{ - LLViewerParcelMgr::getInstance()->sendParcelGodForceToContent(); -} - -void handle_claim_public_land(void*) -{ - if (LLViewerParcelMgr::getInstance()->getSelectionRegion() != gAgent.getRegion()) - { - LLNotificationsUtil::add("ClaimPublicLand"); - return; - } - - LLVector3d west_south_global; - LLVector3d east_north_global; - LLViewerParcelMgr::getInstance()->getSelection(west_south_global, east_north_global); - LLVector3 west_south = gAgent.getPosAgentFromGlobal(west_south_global); - LLVector3 east_north = gAgent.getPosAgentFromGlobal(east_north_global); - - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("GodlikeMessage"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used - msg->nextBlock("MethodData"); - msg->addString("Method", "claimpublicland"); - msg->addUUID("Invoice", LLUUID::null); - std::string buffer; - buffer = llformat( "%f", west_south.mV[VX]); - msg->nextBlock("ParamList"); - msg->addString("Parameter", buffer); - buffer = llformat( "%f", west_south.mV[VY]); - msg->nextBlock("ParamList"); - msg->addString("Parameter", buffer); - buffer = llformat( "%f", east_north.mV[VX]); - msg->nextBlock("ParamList"); - msg->addString("Parameter", buffer); - buffer = llformat( "%f", east_north.mV[VY]); - msg->nextBlock("ParamList"); - msg->addString("Parameter", buffer); - gAgent.sendReliableMessage(); -} - - - -// HACK for easily testing new avatar geometry -void handle_god_request_avatar_geometry(void *) -{ - if (gAgent.isGodlike()) - { - LLSelectMgr::getInstance()->sendGodlikeRequest("avatar toggle", ""); - } -} - - -void derez_objects(EDeRezDestination dest, const LLUUID& dest_id) -{ - if(gAgentCamera.cameraMouselook()) - { - gAgentCamera.changeCameraToDefault(); - } - //gInventoryView->setPanelOpen(TRUE); - - std::string error; - LLDynamicArray<LLViewerObject*> derez_objects; - - // Check conditions that we can't deal with, building a list of - // everything that we'll actually be derezzing. - LLViewerRegion* first_region = NULL; - for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* object = node->getObject(); - LLViewerRegion* region = object->getRegion(); - if (!first_region) - { - first_region = region; - } - else - { - if(region != first_region) - { - // Derez doesn't work at all if the some of the objects - // are in regions besides the first object selected. - - // ...crosses region boundaries - error = "AcquireErrorObjectSpan"; - break; - } - } - if (object->isAvatar()) - { - // ...don't acquire avatars - continue; - } - - // If AssetContainers are being sent back, they will appear as - // boxes in the owner's inventory. - if (object->getNVPair("AssetContainer") - && dest != DRD_RETURN_TO_OWNER) - { - // this object is an asset container, derez its contents, not it - llwarns << "Attempt to derez deprecated AssetContainer object type not supported." << llendl; - /* - object->requestInventory(container_inventory_arrived, - (void *)(BOOL)(DRD_TAKE_INTO_AGENT_INVENTORY == dest)); - */ - continue; - } - BOOL can_derez_current = FALSE; - switch(dest) - { - case DRD_TAKE_INTO_AGENT_INVENTORY: - case DRD_TRASH: - if( (node->mPermissions->allowTransferTo(gAgent.getID()) && object->permModify()) - || (node->allowOperationOnNode(PERM_OWNER, GP_OBJECT_MANIPULATE)) ) - { - can_derez_current = TRUE; - } - break; - - case DRD_RETURN_TO_OWNER: - can_derez_current = TRUE; - break; - - default: - if((node->mPermissions->allowTransferTo(gAgent.getID()) - && object->permCopy()) - || gAgent.isGodlike()) - { - can_derez_current = TRUE; - } - break; - } - if(can_derez_current) - { - derez_objects.put(object); - } - } - - // This constant is based on (1200 - HEADER_SIZE) / 4 bytes per - // root. I lopped off a few (33) to provide a bit - // pad. HEADER_SIZE is currently 67 bytes, most of which is UUIDs. - // This gives us a maximum of 63500 root objects - which should - // satisfy anybody. - const S32 MAX_ROOTS_PER_PACKET = 250; - const S32 MAX_PACKET_COUNT = 254; - F32 packets = ceil((F32)derez_objects.count() / (F32)MAX_ROOTS_PER_PACKET); - if(packets > (F32)MAX_PACKET_COUNT) - { - error = "AcquireErrorTooManyObjects"; - } - - if(error.empty() && derez_objects.count() > 0) - { - U8 d = (U8)dest; - LLUUID tid; - tid.generate(); - U8 packet_count = (U8)packets; - S32 object_index = 0; - S32 objects_in_packet = 0; - LLMessageSystem* msg = gMessageSystem; - for(U8 packet_number = 0; - packet_number < packet_count; - ++packet_number) - { - msg->newMessageFast(_PREHASH_DeRezObject); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_AgentBlock); - msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID()); - msg->addU8Fast(_PREHASH_Destination, d); - msg->addUUIDFast(_PREHASH_DestinationID, dest_id); - msg->addUUIDFast(_PREHASH_TransactionID, tid); - msg->addU8Fast(_PREHASH_PacketCount, packet_count); - msg->addU8Fast(_PREHASH_PacketNumber, packet_number); - objects_in_packet = 0; - while((object_index < derez_objects.count()) - && (objects_in_packet++ < MAX_ROOTS_PER_PACKET)) - - { - LLViewerObject* object = derez_objects.get(object_index++); - msg->nextBlockFast(_PREHASH_ObjectData); - msg->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID()); - // VEFFECT: DerezObject - LLHUDEffectSpiral* effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); - effectp->setPositionGlobal(object->getPositionGlobal()); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - } - msg->sendReliable(first_region->getHost()); - } - make_ui_sound("UISndObjectRezOut"); - - // Busy count decremented by inventory update, so only increment - // if will be causing an update. - if (dest != DRD_RETURN_TO_OWNER) - { - gViewerWindow->getWindow()->incBusyCount(); - } - } - else if(!error.empty()) - { - LLNotificationsUtil::add(error); - } -} - -void handle_take_copy() -{ - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; - - const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); - derez_objects(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id); -} - -// You can return an object to its owner if it is on your land. -class LLObjectReturn : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true; - - mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); - - LLNotificationsUtil::add("ReturnToOwner", LLSD(), LLSD(), boost::bind(&LLObjectReturn::onReturnToOwner, this, _1, _2)); - return true; - } - - bool onReturnToOwner(const LLSD& notification, const LLSD& response) - { - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - // Ignore category ID for this derez destination. - derez_objects(DRD_RETURN_TO_OWNER, LLUUID::null); - } - - // drop reference to current selection - mObjectSelection = NULL; - return false; - } - -protected: - LLObjectSelectionHandle mObjectSelection; -}; - - -// Allow return to owner if one or more of the selected items is -// over land you own. -class LLObjectEnableReturn : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) - { - // Do not enable if nothing selected - return false; - } -#ifdef HACKED_GODLIKE_VIEWER - bool new_value = true; -#else - bool new_value = false; - if (gAgent.isGodlike()) - { - new_value = true; - } - else - { - LLViewerRegion* region = gAgent.getRegion(); - if (region) - { - // Estate owners and managers can always return objects. - if (region->canManageEstate()) - { - new_value = true; - } - else - { - struct f : public LLSelectedObjectFunctor - { - virtual bool apply(LLViewerObject* obj) - { - return - obj->permModify() || - obj->isReturnable(); - } - } func; - const bool firstonly = true; - new_value = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly); - } - } - } -#endif - return new_value; - } -}; - -void force_take_copy(void*) -{ - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; - const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); - derez_objects(DRD_FORCE_TO_GOD_INVENTORY, category_id); -} - -void handle_take() -{ - // we want to use the folder this was derezzed from if it's - // available. Otherwise, derez to the normal place. - if(LLSelectMgr::getInstance()->getSelection()->isEmpty()) - { - return; - } - - BOOL you_own_everything = TRUE; - BOOL locked_but_takeable_object = FALSE; - LLUUID category_id; - - for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* object = node->getObject(); - if(object) - { - if(!object->permYouOwner()) - { - you_own_everything = FALSE; - } - - if(!object->permMove()) - { - locked_but_takeable_object = TRUE; - } - } - if(node->mFolderID.notNull()) - { - if(category_id.isNull()) - { - category_id = node->mFolderID; - } - else if(category_id != node->mFolderID) - { - // we have found two potential destinations. break out - // now and send to the default location. - category_id.setNull(); - break; - } - } - } - if(category_id.notNull()) - { - // there is an unambiguous destination. See if this agent has - // such a location and it is not in the trash or library - if(!gInventory.getCategory(category_id)) - { - // nope, set to NULL. - category_id.setNull(); - } - if(category_id.notNull()) - { - // check trash - const LLUUID trash = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - if(category_id == trash || gInventory.isObjectDescendentOf(category_id, trash)) - { - category_id.setNull(); - } - - // check library - if(gInventory.isObjectDescendentOf(category_id, gInventory.getLibraryRootFolderID())) - { - category_id.setNull(); - } - - } - } - if(category_id.isNull()) - { - category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT); - } - LLSD payload; - payload["folder_id"] = category_id; - - LLNotification::Params params("ConfirmObjectTakeLock"); - params.payload(payload); - params.functor.function(confirm_take); - - if(locked_but_takeable_object || - !you_own_everything) - { - if(locked_but_takeable_object && you_own_everything) - { - params.name("ConfirmObjectTakeLock"); - } - else if(!locked_but_takeable_object && !you_own_everything) - { - params.name("ConfirmObjectTakeNoOwn"); - } - else - { - params.name("ConfirmObjectTakeLockNoOwn"); - } - - LLNotifications::instance().add(params); - } - else - { - LLNotifications::instance().forceResponse(params, 0); - } -} - -void handle_object_show_inspector() -{ - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - LLViewerObject* objectp = selection->getFirstRootObject(TRUE); - if (!objectp) - { - return; - } - - LLSD params; - params["object_id"] = objectp->getID(); - LLFloaterReg::showInstance("inspect_object", params); -} - -void handle_avatar_show_inspector() -{ - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - LLSD params; - params["avatar_id"] = avatar->getID(); - LLFloaterReg::showInstance("inspect_avatar", params); - } -} - - - -bool confirm_take(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if(enable_take() && (option == 0)) - { - derez_objects(DRD_TAKE_INTO_AGENT_INVENTORY, notification["payload"]["folder_id"].asUUID()); - } - return false; -} - -// You can take an item when it is public and transferrable, or when -// you own it. We err on the side of enabling the item when at least -// one item selected can be copied to inventory. -BOOL enable_take() -{ - if (sitting_on_selection()) - { - return FALSE; - } - - for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* object = node->getObject(); - if (object->isAvatar()) - { - // ...don't acquire avatars - continue; - } - -#ifdef HACKED_GODLIKE_VIEWER - return TRUE; -#else -# ifdef TOGGLE_HACKED_GODLIKE_VIEWER - if (!LLGridManager::getInstance()->isInProductionGrid() - && gAgent.isGodlike()) - { - return TRUE; - } -# endif - if((node->mPermissions->allowTransferTo(gAgent.getID()) - && object->permModify()) - || (node->mPermissions->getOwner() == gAgent.getID())) - { - return TRUE; - } -#endif - } - return FALSE; -} - - -void handle_buy_or_take() -{ - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) - { - return; - } - - if (is_selection_buy_not_take()) - { - S32 total_price = selection_price(); - - if (total_price <= gStatusBar->getBalance() || total_price == 0) - { - handle_buy(); - } - else - { - LLStringUtil::format_map_t args; - args["AMOUNT"] = llformat("%d", total_price); - LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString( "BuyingCosts", args ), total_price ); - } - } - else - { - handle_take(); - } -} - -bool visible_buy_object() -{ - return is_selection_buy_not_take() && enable_buy_object(); -} - -bool visible_take_object() -{ - return !is_selection_buy_not_take() && enable_take(); -} - -bool tools_visible_buy_object() -{ - return is_selection_buy_not_take(); -} - -bool tools_visible_take_object() -{ - return !is_selection_buy_not_take(); -} - -class LLToolsEnableBuyOrTake : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool is_buy = is_selection_buy_not_take(); - bool new_value = is_buy ? enable_buy_object() : enable_take(); - return new_value; - } -}; - -// This is a small helper function to determine if we have a buy or a -// take in the selection. This method is to help with the aliasing -// problems of putting buy and take in the same pie menu space. After -// a fair amont of discussion, it was determined to prefer buy over -// take. The reasoning follows from the fact that when users walk up -// to buy something, they will click on one or more items. Thus, if -// anything is for sale, it becomes a buy operation, and the server -// will group all of the buy items, and copyable/modifiable items into -// one package and give the end user as much as the permissions will -// allow. If the user wanted to take something, they will select fewer -// and fewer items until only 'takeable' items are left. The one -// exception is if you own everything in the selection that is for -// sale, in this case, you can't buy stuff from yourself, so you can -// take it. -// return value = TRUE if selection is a 'buy'. -// FALSE if selection is a 'take' -BOOL is_selection_buy_not_take() -{ - for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* obj = node->getObject(); - if(obj && !(obj->permYouOwner()) && (node->mSaleInfo.isForSale())) - { - // you do not own the object and it is for sale, thus, - // it's a buy - return TRUE; - } - } - return FALSE; -} - -S32 selection_price() -{ - S32 total_price = 0; - for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* obj = node->getObject(); - if(obj && !(obj->permYouOwner()) && (node->mSaleInfo.isForSale())) - { - // you do not own the object and it is for sale. - // Add its price. - total_price += node->mSaleInfo.getSalePrice(); - } - } - - return total_price; -} -/* -bool callback_show_buy_currency(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - llinfos << "Loading page " << LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL") << llendl; - LLWeb::loadURL(LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL")); - } - return false; -} -*/ - -void show_buy_currency(const char* extra) -{ - // Don't show currency web page for branded clients. -/* - std::ostringstream mesg; - if (extra != NULL) - { - mesg << extra << "\n \n"; - } - mesg << "Go to " << LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL")<< "\nfor information on purchasing currency?"; -*/ - LLSD args; - if (extra != NULL) - { - args["EXTRA"] = extra; - } - LLNotificationsUtil::add("PromptGoToCurrencyPage", args);//, LLSD(), callback_show_buy_currency); -} - -void handle_buy() -{ - if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return; - - LLSaleInfo sale_info; - BOOL valid = LLSelectMgr::getInstance()->selectGetSaleInfo(sale_info); - if (!valid) return; - - S32 price = sale_info.getSalePrice(); - - if (price > 0 && price > gStatusBar->getBalance()) - { - LLStringUtil::format_map_t args; - args["AMOUNT"] = llformat("%d", price); - LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("this_object_costs", args), price ); - return; - } - - if (sale_info.getSaleType() == LLSaleInfo::FS_CONTENTS) - { - handle_buy_contents(sale_info); - } - else - { - handle_buy_object(sale_info); - } -} - -bool anyone_copy_selection(LLSelectNode* nodep) -{ - bool perm_copy = (bool)(nodep->getObject()->permCopy()); - bool all_copy = (bool)(nodep->mPermissions->getMaskEveryone() & PERM_COPY); - return perm_copy && all_copy; -} - -bool for_sale_selection(LLSelectNode* nodep) -{ - return nodep->mSaleInfo.isForSale() - && nodep->mPermissions->getMaskOwner() & PERM_TRANSFER - && (nodep->mPermissions->getMaskOwner() & PERM_COPY - || nodep->mSaleInfo.getSaleType() != LLSaleInfo::FS_COPY); -} - -BOOL sitting_on_selection() -{ - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if (!node) - { - return FALSE; - } - - if (!node->mValid) - { - return FALSE; - } - - LLViewerObject* root_object = node->getObject(); - if (!root_object) - { - return FALSE; - } - - // Need to determine if avatar is sitting on this object - if (!isAgentAvatarValid()) return FALSE; - - return (gAgentAvatarp->isSitting() && gAgentAvatarp->getRoot() == root_object); -} - -class LLToolsSaveToInventory : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - if(enable_save_into_inventory(NULL)) - { - derez_objects(DRD_SAVE_INTO_AGENT_INVENTORY, LLUUID::null); - } - return true; - } -}; - -class LLToolsSaveToObjectInventory : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if(node && (node->mValid) && (!node->mFromTaskID.isNull())) - { - // *TODO: check to see if the fromtaskid object exists. - derez_objects(DRD_SAVE_INTO_TASK_INVENTORY, node->mFromTaskID); - } - return true; - } -}; - -// Round the position of all root objects to the grid -class LLToolsSnapObjectXY : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - F64 snap_size = (F64)gSavedSettings.getF32("GridResolution"); - - for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* obj = node->getObject(); - if (obj->permModify()) - { - LLVector3d pos_global = obj->getPositionGlobal(); - F64 round_x = fmod(pos_global.mdV[VX], snap_size); - if (round_x < snap_size * 0.5) - { - // closer to round down - pos_global.mdV[VX] -= round_x; - } - else - { - // closer to round up - pos_global.mdV[VX] -= round_x; - pos_global.mdV[VX] += snap_size; - } - - F64 round_y = fmod(pos_global.mdV[VY], snap_size); - if (round_y < snap_size * 0.5) - { - pos_global.mdV[VY] -= round_y; - } - else - { - pos_global.mdV[VY] -= round_y; - pos_global.mdV[VY] += snap_size; - } - - obj->setPositionGlobal(pos_global, FALSE); - } - } - LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_POSITION); - return true; - } -}; - -// Determine if the option to cycle between linked prims is shown -class LLToolsEnableSelectNextPart : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = (gSavedSettings.getBOOL("EditLinkedParts") && - !LLSelectMgr::getInstance()->getSelection()->isEmpty()); - return new_value; - } -}; - -// Cycle selection through linked children in selected object. -// FIXME: Order of children list is not always the same as sim's idea of link order. This may confuse -// resis. Need link position added to sim messages to address this. -class LLToolsSelectNextPart : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - S32 object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); - if (gSavedSettings.getBOOL("EditLinkedParts") && object_count) - { - LLViewerObject* selected = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); - if (selected && selected->getRootEdit()) - { - bool fwd = (userdata.asString() == "next"); - bool prev = (userdata.asString() == "previous"); - bool ifwd = (userdata.asString() == "includenext"); - bool iprev = (userdata.asString() == "includeprevious"); - LLViewerObject* to_select = NULL; - LLViewerObject::child_list_t children = selected->getRootEdit()->getChildren(); - children.push_front(selected->getRootEdit()); // need root in the list too - - for (LLViewerObject::child_list_t::iterator iter = children.begin(); iter != children.end(); ++iter) - { - if ((*iter)->isSelected()) - { - if (object_count > 1 && (fwd || prev)) // multiple selection, find first or last selected if not include - { - to_select = *iter; - if (fwd) - { - // stop searching if going forward; repeat to get last hit if backward - break; - } - } - else if ((object_count == 1) || (ifwd || iprev)) // single selection or include - { - if (fwd || ifwd) - { - ++iter; - while (iter != children.end() && ((*iter)->isAvatar() || (ifwd && (*iter)->isSelected()))) - { - ++iter; // skip sitting avatars and selected if include - } - } - else // backward - { - iter = (iter == children.begin() ? children.end() : iter); - --iter; - while (iter != children.begin() && ((*iter)->isAvatar() || (iprev && (*iter)->isSelected()))) - { - --iter; // skip sitting avatars and selected if include - } - } - iter = (iter == children.end() ? children.begin() : iter); - to_select = *iter; - break; - } - } - } - - if (to_select) - { - if (gFocusMgr.childHasKeyboardFocus(gFloaterTools)) - { - gFocusMgr.setKeyboardFocus(NULL); // force edit toolbox to commit any changes - } - if (fwd || prev) - { - LLSelectMgr::getInstance()->deselectAll(); - } - LLSelectMgr::getInstance()->selectObjectOnly(to_select); - return true; - } - } - } - return true; - } -}; - -class LLToolsStopAllAnimations : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - gAgent.stopCurrentAnimations(); - return true; - } -}; - -class LLToolsReleaseKeys : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - gAgent.forceReleaseControls(); - - return true; - } -}; - -class LLToolsEnableReleaseKeys : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - return gAgent.anyControlGrabbed(); - } -}; - - -class LLEditEnableCut : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCut(); - return new_value; - } -}; - -class LLEditCut : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler ) - { - LLEditMenuHandler::gEditMenuHandler->cut(); - } - return true; - } -}; - -class LLEditEnableCopy : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCopy(); - return new_value; - } -}; - -class LLEditCopy : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler ) - { - LLEditMenuHandler::gEditMenuHandler->copy(); - } - return true; - } -}; - -class LLEditEnablePaste : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canPaste(); - return new_value; - } -}; - -class LLEditPaste : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler ) - { - LLEditMenuHandler::gEditMenuHandler->paste(); - } - return true; - } -}; - -class LLEditEnableDelete : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDoDelete(); - return new_value; - } -}; - -class LLEditDelete : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - // If a text field can do a deletion, it gets precedence over deleting - // an object in the world. - if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDoDelete()) - { - LLEditMenuHandler::gEditMenuHandler->doDelete(); - } - - // and close any pie/context menus when done - gMenuHolder->hideMenus(); - - // When deleting an object we may not actually be done - // Keep selection so we know what to delete when confirmation is needed about the delete - gMenuObject->hide(); - return true; - } -}; - -bool enable_object_delete() -{ - bool new_value = -#ifdef HACKED_GODLIKE_VIEWER - TRUE; -#else -# ifdef TOGGLE_HACKED_GODLIKE_VIEWER - (!LLGridManager::getInstance()->isInProductionGrid() - && gAgent.isGodlike()) || -# endif - LLSelectMgr::getInstance()->canDoDelete(); -#endif - return new_value; -} - -void handle_object_delete() -{ - - if (LLSelectMgr::getInstance()) - { - LLSelectMgr::getInstance()->doDelete(); - } - - // and close any pie/context menus when done - gMenuHolder->hideMenus(); - - // When deleting an object we may not actually be done - // Keep selection so we know what to delete when confirmation is needed about the delete - gMenuObject->hide(); - return; -} - -void handle_force_delete(void*) -{ - LLSelectMgr::getInstance()->selectForceDelete(); -} - -class LLViewEnableJoystickFlycam : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = (gSavedSettings.getBOOL("JoystickEnabled") && gSavedSettings.getBOOL("JoystickFlycamEnabled")); - return new_value; - } -}; - -class LLViewEnableLastChatter : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - // *TODO: add check that last chatter is in range - bool new_value = (gAgentCamera.cameraThirdPerson() && gAgent.getLastChatter().notNull()); - return new_value; - } -}; - -class LLEditEnableDeselect : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDeselect(); - return new_value; - } -}; - -class LLEditDeselect : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler ) - { - LLEditMenuHandler::gEditMenuHandler->deselect(); - } - return true; - } -}; - -class LLEditEnableSelectAll : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canSelectAll(); - return new_value; - } -}; - - -class LLEditSelectAll : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler ) - { - LLEditMenuHandler::gEditMenuHandler->selectAll(); - } - return true; - } -}; - - -class LLEditEnableUndo : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo(); - return new_value; - } -}; - -class LLEditUndo : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo() ) - { - LLEditMenuHandler::gEditMenuHandler->undo(); - } - return true; - } -}; - -class LLEditEnableRedo : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo(); - return new_value; - } -}; - -class LLEditRedo : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo() ) - { - LLEditMenuHandler::gEditMenuHandler->redo(); - } - return true; - } -}; - - - -void print_object_info(void*) -{ - LLSelectMgr::getInstance()->selectionDump(); -} - -void print_agent_nvpairs(void*) -{ - LLViewerObject *objectp; - - llinfos << "Agent Name Value Pairs" << llendl; - - objectp = gObjectList.findObject(gAgentID); - if (objectp) - { - objectp->printNameValuePairs(); - } - else - { - llinfos << "Can't find agent object" << llendl; - } - - llinfos << "Camera at " << gAgentCamera.getCameraPositionGlobal() << llendl; -} - -void show_debug_menus() -{ - // this might get called at login screen where there is no menu so only toggle it if one exists - if ( gMenuBarView ) - { - BOOL debug = gSavedSettings.getBOOL("UseDebugMenus"); - BOOL qamode = gSavedSettings.getBOOL("QAMode"); - - gMenuBarView->setItemVisible("Advanced", debug); -// gMenuBarView->setItemEnabled("Advanced", debug); // Don't disable Advanced keyboard shortcuts when hidden - - gMenuBarView->setItemVisible("Debug", qamode); - gMenuBarView->setItemEnabled("Debug", qamode); - - gMenuBarView->setItemVisible("Develop", qamode); - gMenuBarView->setItemEnabled("Develop", qamode); - - // Server ('Admin') menu hidden when not in godmode. - const bool show_server_menu = (gAgent.getGodLevel() > GOD_NOT || (debug && gAgent.getAdminOverride())); - gMenuBarView->setItemVisible("Admin", show_server_menu); - gMenuBarView->setItemEnabled("Admin", show_server_menu); - } - if (gLoginMenuBarView) - { - BOOL debug = gSavedSettings.getBOOL("UseDebugMenus"); - gLoginMenuBarView->setItemVisible("Debug", debug); - gLoginMenuBarView->setItemEnabled("Debug", debug); - } -} - -void toggle_debug_menus(void*) -{ - BOOL visible = ! gSavedSettings.getBOOL("UseDebugMenus"); - gSavedSettings.setBOOL("UseDebugMenus", visible); - show_debug_menus(); -} - - -// LLUUID gExporterRequestID; -// std::string gExportDirectory; - -// LLUploadDialog *gExportDialog = NULL; - -// void handle_export_selected( void * ) -// { -// LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); -// if (selection->isEmpty()) -// { -// return; -// } -// llinfos << "Exporting selected objects:" << llendl; - -// gExporterRequestID.generate(); -// gExportDirectory = ""; - -// LLMessageSystem* msg = gMessageSystem; -// msg->newMessageFast(_PREHASH_ObjectExportSelected); -// msg->nextBlockFast(_PREHASH_AgentData); -// msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); -// msg->addUUIDFast(_PREHASH_RequestID, gExporterRequestID); -// msg->addS16Fast(_PREHASH_VolumeDetail, 4); - -// for (LLObjectSelection::root_iterator iter = selection->root_begin(); -// iter != selection->root_end(); iter++) -// { -// LLSelectNode* node = *iter; -// LLViewerObject* object = node->getObject(); -// msg->nextBlockFast(_PREHASH_ObjectData); -// msg->addUUIDFast(_PREHASH_ObjectID, object->getID()); -// llinfos << "Object: " << object->getID() << llendl; -// } -// msg->sendReliable(gAgent.getRegion()->getHost()); - -// gExportDialog = LLUploadDialog::modalUploadDialog("Exporting selected objects..."); -// } -// - - -class LLWorldSetHomeLocation : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - // we just send the message and let the server check for failure cases - // server will echo back a "Home position set." alert if it succeeds - // and the home location screencapture happens when that alert is recieved - gAgent.setStartPosition(START_LOCATION_ID_HOME); - return true; - } -}; - -class LLWorldTeleportHome : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - gAgent.teleportHome(); - return true; - } -}; - -class LLWorldAlwaysRun : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - // as well as altering the default walk-vs-run state, - // we also change the *current* walk-vs-run state. - if (gAgent.getAlwaysRun()) - { - gAgent.clearAlwaysRun(); - gAgent.clearRunning(); - } - else - { - gAgent.setAlwaysRun(); - gAgent.setRunning(); - } - - // tell the simulator. - gAgent.sendWalkRun(gAgent.getAlwaysRun()); - - // Update Movement Controls according to AlwaysRun mode - LLFloaterMove::setAlwaysRunMode(gAgent.getAlwaysRun()); - - return true; - } -}; - -class LLWorldCheckAlwaysRun : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = gAgent.getAlwaysRun(); - return new_value; - } -}; - -class LLWorldSetAway : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - if (gAgent.getAFK()) - { - gAgent.clearAFK(); - } - else - { - gAgent.setAFK(); - } - return true; - } -}; - -class LLWorldSetBusy : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - if (gAgent.getBusy()) - { - gAgent.clearBusy(); - } - else - { - gAgent.setBusy(); - LLNotificationsUtil::add("BusyModeSet"); - } - return true; - } -}; - -class LLWorldCreateLandmark : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLSideTray::getInstance()->showPanel("panel_places", LLSD().with("type", "create_landmark")); - - return true; - } -}; - -class LLWorldPlaceProfile : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLSideTray::getInstance()->showPanel("panel_places", LLSD().with("type", "agent")); - - return true; - } -}; - -void handle_look_at_selection(const LLSD& param) -{ - const F32 PADDING_FACTOR = 1.75f; - BOOL zoom = (param.asString() == "zoom"); - if (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) - { - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); - - LLBBox selection_bbox = LLSelectMgr::getInstance()->getBBoxOfSelection(); - F32 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getAspect() > 1.f ? LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect() : LLViewerCamera::getInstance()->getView()); - F32 distance = selection_bbox.getExtentLocal().magVec() * PADDING_FACTOR / atan(angle_of_view); - - LLVector3 obj_to_cam = LLViewerCamera::getInstance()->getOrigin() - selection_bbox.getCenterAgent(); - obj_to_cam.normVec(); - - LLUUID object_id; - if (LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()) - { - object_id = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()->mID; - } - if (zoom) - { - // Make sure we are not increasing the distance between the camera and object - LLVector3d orig_distance = gAgentCamera.getCameraPositionGlobal() - LLSelectMgr::getInstance()->getSelectionCenterGlobal(); - distance = llmin(distance, (F32) orig_distance.length()); - - gAgentCamera.setCameraPosAndFocusGlobal(LLSelectMgr::getInstance()->getSelectionCenterGlobal() + LLVector3d(obj_to_cam * distance), - LLSelectMgr::getInstance()->getSelectionCenterGlobal(), - object_id ); - - } - else - { - gAgentCamera.setFocusGlobal( LLSelectMgr::getInstance()->getSelectionCenterGlobal(), object_id ); - } - } -} - -void handle_zoom_to_object(LLUUID object_id) -{ - const F32 PADDING_FACTOR = 2.f; - - LLViewerObject* object = gObjectList.findObject(object_id); - - if (object) - { - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); - - LLBBox bbox = object->getBoundingBoxAgent() ; - F32 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getAspect() > 1.f ? LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect() : LLViewerCamera::getInstance()->getView()); - F32 distance = bbox.getExtentLocal().magVec() * PADDING_FACTOR / atan(angle_of_view); - - LLVector3 obj_to_cam = LLViewerCamera::getInstance()->getOrigin() - bbox.getCenterAgent(); - obj_to_cam.normVec(); - - - LLVector3d object_center_global = gAgent.getPosGlobalFromAgent(bbox.getCenterAgent()); - - gAgentCamera.setCameraPosAndFocusGlobal(object_center_global + LLVector3d(obj_to_cam * distance), - object_center_global, - object_id ); - } -} - -class LLAvatarInviteToGroup : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - LLAvatarActions::inviteToGroup(avatar->getID()); - } - return true; - } -}; - -class LLAvatarAddFriend : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar && !LLAvatarActions::isFriend(avatar->getID())) - { - request_friendship(avatar->getID()); - } - return true; - } -}; - -class LLAvatarAddContact : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - create_inventory_callingcard(avatar->getID()); - } - return true; - } -}; - -bool complete_give_money(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle selection) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option == 0) - { - gAgent.clearBusy(); - } - - LLViewerObject* objectp = selection->getPrimaryObject(); - - // Show avatar's name if paying attachment - if (objectp && objectp->isAttachment()) - { - while (objectp && !objectp->isAvatar()) - { - objectp = (LLViewerObject*)objectp->getParent(); - } - } - - if (objectp) - { - if (objectp->isAvatar()) - { - const bool is_group = false; - LLFloaterPayUtil::payDirectly(&give_money, - objectp->getID(), - is_group); - } - else - { - LLFloaterPayUtil::payViaObject(&give_money, selection); - } - } - return false; -} - -void handle_give_money_dialog() -{ - LLNotification::Params params("BusyModePay"); - params.functor.function(boost::bind(complete_give_money, _1, _2, LLSelectMgr::getInstance()->getSelection())); - - if (gAgent.getBusy()) - { - // warn users of being in busy mode during a transaction - LLNotifications::instance().add(params); - } - else - { - LLNotifications::instance().forceResponse(params, 1); - } -} - -bool enable_pay_avatar() -{ - LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - LLVOAvatar* avatar = find_avatar_from_object(obj); - return (avatar != NULL); -} - -bool enable_pay_object() -{ - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if( object ) - { - LLViewerObject *parent = (LLViewerObject *)object->getParent(); - if((object->flagTakesMoney()) || (parent && parent->flagTakesMoney())) - { - return true; - } - } - return false; -} - -bool enable_object_stand_up() -{ - // 'Object Stand Up' menu item is enabled when agent is sitting on selection - return sitting_on_selection(); -} - -bool enable_object_sit(LLUICtrl* ctrl) -{ - // 'Object Sit' menu item is enabled when agent is not sitting on selection - bool sitting_on_sel = sitting_on_selection(); - if (!sitting_on_sel) - { - std::string item_name = ctrl->getName(); - - // init default labels - init_default_item_label(item_name); - - // Update label - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if (node && node->mValid && !node->mSitName.empty()) - { - gMenuHolder->childSetText(item_name, node->mSitName); - } - else - { - gMenuHolder->childSetText(item_name, get_default_item_label(item_name)); - } - } - return !sitting_on_sel && is_object_sittable(); -} - -void dump_select_mgr(void*) -{ - LLSelectMgr::getInstance()->dump(); -} - -void dump_inventory(void*) -{ - gInventory.dumpInventory(); -} - - -void handle_dump_followcam(void*) -{ - LLFollowCamMgr::dump(); -} - -void handle_viewer_enable_message_log(void*) -{ - gMessageSystem->startLogging(); -} - -void handle_viewer_disable_message_log(void*) -{ - gMessageSystem->stopLogging(); -} - -void handle_customize_avatar() -{ - LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "my_outfits")); -} - -void handle_edit_outfit() -{ - LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_outfit")); -} - -void handle_edit_shape() -{ - LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_shape")); -} - -void handle_report_abuse() -{ - // Prevent menu from appearing in screen shot. - gMenuHolder->hideMenus(); - LLFloaterReporter::showFromMenu(COMPLAINT_REPORT); -} - -void handle_buy_currency() -{ - LLBuyCurrencyHTML::openCurrencyFloater(); -} - -class LLFloaterVisible : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string floater_name = userdata.asString(); - bool new_value = false; - { - new_value = LLFloaterReg::instanceVisible(floater_name); - } - return new_value; - } -}; - -class LLShowHelp : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string help_topic = userdata.asString(); - LLViewerHelp* vhelp = LLViewerHelp::getInstance(); - vhelp->showTopic(help_topic); - return true; - } -}; - -class LLToggleHelp : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLFloater* help_browser = (LLFloaterReg::findInstance("help_browser")); - if (help_browser && help_browser->isInVisibleChain()) - { - help_browser->closeFloater(); - } - else - { - std::string help_topic = userdata.asString(); - LLViewerHelp* vhelp = LLViewerHelp::getInstance(); - vhelp->showTopic(help_topic); - } - return true; - } -}; - -class LLShowSidetrayPanel : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string panel_name = userdata.asString(); - - LLPanel* panel = LLSideTray::getInstance()->getPanel(panel_name); - if (panel) - { - if (panel->isInVisibleChain()) - { - LLSideTray::getInstance()->hidePanel(panel_name); - } - else - { - LLSideTray::getInstance()->showPanel(panel_name); - } - } - return true; - } -}; - -class LLSidetrayPanelVisible : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string panel_name = userdata.asString(); - // Toggle the panel - if (LLSideTray::getInstance()->isPanelActive(panel_name)) - { - return true; - } - else - { - return false; - } - - } -}; - - -bool callback_show_url(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - LLWeb::loadURL(notification["payload"]["url"].asString()); - } - return false; -} - -class LLPromptShowURL : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string param = userdata.asString(); - std::string::size_type offset = param.find(","); - if (offset != param.npos) - { - std::string alert = param.substr(0, offset); - std::string url = param.substr(offset+1); - - if(gSavedSettings.getBOOL("UseExternalBrowser")) - { - LLSD payload; - payload["url"] = url; - LLNotificationsUtil::add(alert, LLSD(), payload, callback_show_url); - } - else - { - LLWeb::loadURL(url); - } - } - else - { - llinfos << "PromptShowURL invalid parameters! Expecting \"ALERT,URL\"." << llendl; - } - return true; - } -}; - -bool callback_show_file(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - LLWeb::loadURL(notification["payload"]["url"]); - } - return false; -} - -class LLPromptShowFile : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string param = userdata.asString(); - std::string::size_type offset = param.find(","); - if (offset != param.npos) - { - std::string alert = param.substr(0, offset); - std::string file = param.substr(offset+1); - - LLSD payload; - payload["url"] = file; - LLNotificationsUtil::add(alert, LLSD(), payload, callback_show_file); - } - else - { - llinfos << "PromptShowFile invalid parameters! Expecting \"ALERT,FILE\"." << llendl; - } - return true; - } -}; - -class LLShowAgentProfile : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLUUID agent_id; - if (userdata.asString() == "agent") - { - agent_id = gAgent.getID(); - } - else if (userdata.asString() == "hit object") - { - LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (objectp) - { - agent_id = objectp->getID(); - } - } - else - { - agent_id = userdata.asUUID(); - } - - LLVOAvatar* avatar = find_avatar_from_object(agent_id); - if (avatar) - { - LLAvatarActions::showProfile(avatar->getID()); - } - return true; - } -}; - -class LLToggleAgentProfile : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLUUID agent_id; - if (userdata.asString() == "agent") - { - agent_id = gAgent.getID(); - } - else if (userdata.asString() == "hit object") - { - LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (objectp) - { - agent_id = objectp->getID(); - } - } - else - { - agent_id = userdata.asUUID(); - } - - LLVOAvatar* avatar = find_avatar_from_object(agent_id); - if (avatar) - { - if (!LLAvatarActions::profileVisible(avatar->getID())) - { - LLAvatarActions::showProfile(avatar->getID()); - } - else - { - LLAvatarActions::hideProfile(avatar->getID()); - } - } - return true; - } -}; - -class LLLandEdit : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - if (gAgentCamera.getFocusOnAvatar() && gSavedSettings.getBOOL("EditCameraMovement") ) - { - // zoom in if we're looking at the avatar - gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE); - gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); - - gAgentCamera.cameraOrbitOver( F_PI * 0.25f ); - gViewerWindow->moveCursorToCenter(); - } - else if ( gSavedSettings.getBOOL("EditCameraMovement") ) - { - gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick()); - gViewerWindow->moveCursorToCenter(); - } - - - LLViewerParcelMgr::getInstance()->selectParcelAt( LLToolPie::getInstance()->getPick().mPosGlobal ); - - LLFloaterReg::showInstance("build"); - - // Switch to land edit toolset - LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolSelectLand::getInstance() ); - return true; - } -}; - -class LLWorldEnableBuyLand : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLViewerParcelMgr::getInstance()->canAgentBuyParcel( - LLViewerParcelMgr::getInstance()->selectionEmpty() - ? LLViewerParcelMgr::getInstance()->getAgentParcel() - : LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(), - false); - return new_value; - } -}; - -BOOL enable_buy_land(void*) -{ - return LLViewerParcelMgr::getInstance()->canAgentBuyParcel( - LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(), false); -} - -void handle_buy_land() -{ - LLViewerParcelMgr* vpm = LLViewerParcelMgr::getInstance(); - if (vpm->selectionEmpty()) - { - vpm->selectParcelAt(gAgent.getPositionGlobal()); - } - vpm->startBuyLand(); -} - -class LLObjectAttachToAvatar : public view_listener_t -{ -public: - LLObjectAttachToAvatar(bool replace) : mReplace(replace) {} - static void setObjectSelection(LLObjectSelectionHandle selection) { sObjectSelection = selection; } - -private: - bool handleEvent(const LLSD& userdata) - { - setObjectSelection(LLSelectMgr::getInstance()->getSelection()); - LLViewerObject* selectedObject = sObjectSelection->getFirstRootObject(); - if (selectedObject) - { - S32 index = userdata.asInteger(); - LLViewerJointAttachment* attachment_point = NULL; - if (index > 0) - attachment_point = get_if_there(gAgentAvatarp->mAttachmentPoints, index, (LLViewerJointAttachment*)NULL); - confirmReplaceAttachment(0, attachment_point); - } - return true; - } - - static void onNearAttachObject(BOOL success, void *user_data); - void confirmReplaceAttachment(S32 option, LLViewerJointAttachment* attachment_point); - - struct CallbackData - { - CallbackData(LLViewerJointAttachment* point, bool replace) : mAttachmentPoint(point), mReplace(replace) {} - - LLViewerJointAttachment* mAttachmentPoint; - bool mReplace; - }; - -protected: - static LLObjectSelectionHandle sObjectSelection; - bool mReplace; -}; - -LLObjectSelectionHandle LLObjectAttachToAvatar::sObjectSelection; - -// static -void LLObjectAttachToAvatar::onNearAttachObject(BOOL success, void *user_data) -{ - if (!user_data) return; - CallbackData* cb_data = static_cast<CallbackData*>(user_data); - - if (success) - { - const LLViewerJointAttachment *attachment = cb_data->mAttachmentPoint; - - U8 attachment_id = 0; - if (attachment) - { - for (LLVOAvatar::attachment_map_t::const_iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); - iter != gAgentAvatarp->mAttachmentPoints.end(); ++iter) - { - if (iter->second == attachment) - { - attachment_id = iter->first; - break; - } - } - } - else - { - // interpret 0 as "default location" - attachment_id = 0; - } - LLSelectMgr::getInstance()->sendAttach(attachment_id, cb_data->mReplace); - } - LLObjectAttachToAvatar::setObjectSelection(NULL); - - delete cb_data; -} - -// static -void LLObjectAttachToAvatar::confirmReplaceAttachment(S32 option, LLViewerJointAttachment* attachment_point) -{ - if (option == 0/*YES*/) - { - LLViewerObject* selectedObject = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject(); - if (selectedObject) - { - const F32 MIN_STOP_DISTANCE = 1.f; // meters - const F32 ARM_LENGTH = 0.5f; // meters - const F32 SCALE_FUDGE = 1.5f; - - F32 stop_distance = SCALE_FUDGE * selectedObject->getMaxScale() + ARM_LENGTH; - if (stop_distance < MIN_STOP_DISTANCE) - { - stop_distance = MIN_STOP_DISTANCE; - } - - LLVector3 walkToSpot = selectedObject->getPositionAgent(); - - // make sure we stop in front of the object - LLVector3 delta = walkToSpot - gAgent.getPositionAgent(); - delta.normVec(); - delta = delta * 0.5f; - walkToSpot -= delta; - - // The callback will be called even if avatar fails to get close enough to the object, so we won't get a memory leak. - CallbackData* user_data = new CallbackData(attachment_point, mReplace); - gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(walkToSpot), "Attach", NULL, onNearAttachObject, user_data, stop_distance); - gAgentCamera.clearFocusObject(); - } - } -} - -void callback_attachment_drop(const LLSD& notification, const LLSD& response) -{ - // Ensure user confirmed the drop - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option != 0) return; - - // Called when the user clicked on an object attached to them - // and selected "Drop". - LLUUID object_id = notification["payload"]["object_id"].asUUID(); - LLViewerObject *object = gObjectList.findObject(object_id); - - if (!object) - { - llwarns << "handle_drop_attachment() - no object to drop" << llendl; - return; - } - - LLViewerObject *parent = (LLViewerObject*)object->getParent(); - while (parent) - { - if(parent->isAvatar()) - { - break; - } - object = parent; - parent = (LLViewerObject*)parent->getParent(); - } - - if (!object) - { - llwarns << "handle_detach() - no object to detach" << llendl; - return; - } - - if (object->isAvatar()) - { - llwarns << "Trying to detach avatar from avatar." << llendl; - return; - } - - // reselect the object - LLSelectMgr::getInstance()->selectObjectAndFamily(object); - - LLSelectMgr::getInstance()->sendDropAttachment(); - - return; -} - -class LLAttachmentDrop : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLSD payload; - LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - - if (object) - { - payload["object_id"] = object->getID(); - } - else - { - llwarns << "Drop object not found" << llendl; - return true; - } - - LLNotificationsUtil::add("AttachmentDrop", LLSD(), payload, &callback_attachment_drop); - return true; - } -}; - -// called from avatar pie menu -class LLAttachmentDetachFromPoint : public view_listener_t -{ - bool handleEvent(const LLSD& user_data) - { - const LLViewerJointAttachment *attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, user_data.asInteger(), (LLViewerJointAttachment*)NULL); - if (attachment->getNumObjects() > 0) - { - gMessageSystem->newMessage("ObjectDetach"); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - - for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator iter = attachment->mAttachedObjects.begin(); - iter != attachment->mAttachedObjects.end(); - iter++) - { - LLViewerObject *attached_object = (*iter); - gMessageSystem->nextBlockFast(_PREHASH_ObjectData); - gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, attached_object->getLocalID()); - } - gMessageSystem->sendReliable( gAgent.getRegionHost() ); - } - return true; - } -}; - -static bool onEnableAttachmentLabel(LLUICtrl* ctrl, const LLSD& data) -{ - std::string label; - LLMenuItemGL* menu = dynamic_cast<LLMenuItemGL*>(ctrl); - if (menu) - { - const LLViewerJointAttachment *attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, data["index"].asInteger(), (LLViewerJointAttachment*)NULL); - if (attachment) - { - label = data["label"].asString(); - for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - const LLViewerObject* attached_object = (*attachment_iter); - if (attached_object) - { - LLViewerInventoryItem* itemp = gInventory.getItem(attached_object->getAttachmentItemID()); - if (itemp) - { - label += std::string(" (") + itemp->getName() + std::string(")"); - break; - } - } - } - } - menu->setLabel(label); - } - return true; -} - -class LLAttachmentDetach : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - // Called when the user clicked on an object attached to them - // and selected "Detach". - LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (!object) - { - llwarns << "handle_detach() - no object to detach" << llendl; - return true; - } - - LLViewerObject *parent = (LLViewerObject*)object->getParent(); - while (parent) - { - if(parent->isAvatar()) - { - break; - } - object = parent; - parent = (LLViewerObject*)parent->getParent(); - } - - if (!object) - { - llwarns << "handle_detach() - no object to detach" << llendl; - return true; - } - - if (object->isAvatar()) - { - llwarns << "Trying to detach avatar from avatar." << llendl; - return true; - } - - // The sendDetach() method works on the list of selected - // objects. Thus we need to clear the list, make sure it only - // contains the object the user clicked, send the message, - // then clear the list. - // We use deselectAll to update the simulator's notion of what's - // selected, and removeAll just to change things locally. - //RN: I thought it was more useful to detach everything that was selected - if (LLSelectMgr::getInstance()->getSelection()->isAttachment()) - { - LLSelectMgr::getInstance()->sendDetach(); - } - return true; - } -}; - -//Adding an observer for a Jira 2422 and needs to be a fetch observer -//for Jira 3119 -class LLWornItemFetchedObserver : public LLInventoryFetchItemsObserver -{ -public: - LLWornItemFetchedObserver(const LLUUID& worn_item_id) : - LLInventoryFetchItemsObserver(worn_item_id) - {} - virtual ~LLWornItemFetchedObserver() {} - -protected: - virtual void done() - { - gMenuAttachmentSelf->buildDrawLabels(); - gInventory.removeObserver(this); - delete this; - } -}; - -// You can only drop items on parcels where you can build. -class LLAttachmentEnableDrop : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - BOOL can_build = gAgent.isGodlike() || (LLViewerParcelMgr::getInstance()->allowAgentBuild()); - - //Add an inventory observer to only allow dropping the newly attached item - //once it exists in your inventory. Look at Jira 2422. - //-jwolk - - // A bug occurs when you wear/drop an item before it actively is added to your inventory - // if this is the case (you're on a slow sim, etc.) a copy of the object, - // well, a newly created object with the same properties, is placed - // in your inventory. Therefore, we disable the drop option until the - // item is in your inventory - - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - LLViewerJointAttachment* attachment = NULL; - LLInventoryItem* item = NULL; - - // Do not enable drop if all faces of object are not enabled - if (object && LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES )) - { - S32 attachmentID = ATTACHMENT_ID_FROM_STATE(object->getState()); - attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL); - - if (attachment) - { - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - // make sure item is in your inventory (it could be a delayed attach message being sent from the sim) - // so check to see if the item is in the inventory already - item = gInventory.getItem((*attachment_iter)->getAttachmentItemID()); - if (!item) - { - // Item does not exist, make an observer to enable the pie menu - // when the item finishes fetching worst case scenario - // if a fetch is already out there (being sent from a slow sim) - // we refetch and there are 2 fetches - LLWornItemFetchedObserver* worn_item_fetched = new LLWornItemFetchedObserver((*attachment_iter)->getAttachmentItemID()); - worn_item_fetched->startFetch(); - gInventory.addObserver(worn_item_fetched); - } - } - } - } - - //now check to make sure that the item is actually in the inventory before we enable dropping it - bool new_value = enable_detach() && can_build && item; - - return new_value; - } -}; - -BOOL enable_detach(const LLSD&) -{ - LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - - // Only enable detach if all faces of object are selected - if (!object || - !object->isAttachment() || - !LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES )) - { - return FALSE; - } - - // Find the avatar who owns this attachment - LLViewerObject* avatar = object; - while (avatar) - { - // ...if it's you, good to detach - if (avatar->getID() == gAgent.getID()) - { - return TRUE; - } - - avatar = (LLViewerObject*)avatar->getParent(); - } - - return FALSE; -} - -class LLAttachmentEnableDetach : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = enable_detach(); - return new_value; - } -}; - -// Used to tell if the selected object can be attached to your avatar. -BOOL object_selected_and_point_valid() -{ - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - for (LLObjectSelection::root_iterator iter = selection->root_begin(); - iter != selection->root_end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* object = node->getObject(); - LLViewerObject::const_child_list_t& child_list = object->getChildren(); - for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); - iter != child_list.end(); iter++) - { - LLViewerObject* child = *iter; - if (child->isAvatar()) - { - return FALSE; - } - } - } - - return (selection->getRootObjectCount() == 1) && - (selection->getFirstRootObject()->getPCode() == LL_PCODE_VOLUME) && - selection->getFirstRootObject()->permYouOwner() && - selection->getFirstRootObject()->flagObjectMove() && - !((LLViewerObject*)selection->getFirstRootObject()->getRoot())->isAvatar() && - (selection->getFirstRootObject()->getNVPair("AssetContainer") == NULL); -} - - -BOOL object_is_wearable() -{ - if (!object_selected_and_point_valid()) - { - return FALSE; - } - if (sitting_on_selection()) - { - return FALSE; - } - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++) - { - LLSelectNode* node = *iter; - if (node->mPermissions->getOwner() == gAgent.getID()) - { - return TRUE; - } - } - return FALSE; -} - - -class LLAttachmentPointFilled : public view_listener_t -{ - bool handleEvent(const LLSD& user_data) - { - bool enable = false; - LLVOAvatar::attachment_map_t::iterator found_it = gAgentAvatarp->mAttachmentPoints.find(user_data.asInteger()); - if (found_it != gAgentAvatarp->mAttachmentPoints.end()) - { - enable = found_it->second->getNumObjects() > 0; - } - return enable; - } -}; - -class LLAvatarSendIM : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - LLAvatarActions::startIM(avatar->getID()); - } - return true; - } -}; - -class LLAvatarCall : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - LLAvatarActions::startCall(avatar->getID()); - } - return true; - } -}; - -namespace -{ - struct QueueObjects : public LLSelectedObjectFunctor - { - BOOL scripted; - BOOL modifiable; - LLFloaterScriptQueue* mQueue; - QueueObjects(LLFloaterScriptQueue* q) : mQueue(q), scripted(FALSE), modifiable(FALSE) {} - virtual bool apply(LLViewerObject* obj) - { - scripted = obj->flagScripted(); - modifiable = obj->permModify(); - - if( scripted && modifiable ) - { - mQueue->addObject(obj->getID()); - return false; - } - else - { - return true; // fail: stop applying - } - } - }; -} - -void queue_actions(LLFloaterScriptQueue* q, const std::string& msg) -{ - QueueObjects func(q); - LLSelectMgr *mgr = LLSelectMgr::getInstance(); - LLObjectSelectionHandle selectHandle = mgr->getSelection(); - bool fail = selectHandle->applyToObjects(&func); - if(fail) - { - if ( !func.scripted ) - { - std::string noscriptmsg = std::string("Cannot") + msg + "SelectObjectsNoScripts"; - LLNotificationsUtil::add(noscriptmsg); - } - else if ( !func.modifiable ) - { - std::string nomodmsg = std::string("Cannot") + msg + "SelectObjectsNoPermission"; - LLNotificationsUtil::add(nomodmsg); - } - else - { - llerrs << "Bad logic." << llendl; - } - } - else - { - if (!q->start()) - { - llwarns << "Unexpected script compile failure." << llendl; - } - } -} - -class LLToolsSelectedScriptAction : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string action = userdata.asString(); - bool mono = false; - std::string msg, name; - if (action == "compile mono") - { - name = "compile_queue"; - mono = true; - msg = "Recompile"; - } - if (action == "compile lsl") - { - name = "compile_queue"; - msg = "Recompile"; - } - else if (action == "reset") - { - name = "reset_queue"; - msg = "Reset"; - } - else if (action == "start") - { - name = "start_queue"; - msg = "Running"; - } - else if (action == "stop") - { - name = "stop_queue"; - msg = "RunningNot"; - } - LLUUID id; id.generate(); - - LLFloaterScriptQueue* queue =LLFloaterReg::getTypedInstance<LLFloaterScriptQueue>(name, LLSD(id)); - if (queue) - { - queue->setMono(mono); - queue_actions(queue, msg); - } - else - { - llwarns << "Failed to generate LLFloaterScriptQueue with action: " << action << llendl; - } - return true; - } -}; - -void handle_selected_texture_info(void*) -{ - for (LLObjectSelection::valid_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->valid_end(); iter++) - { - LLSelectNode* node = *iter; - - std::string msg; - msg.assign("Texture info for: "); - msg.append(node->mName); - - LLSD args; - args["MESSAGE"] = msg; - LLNotificationsUtil::add("SystemMessage", args); - - U8 te_count = node->getObject()->getNumTEs(); - // map from texture ID to list of faces using it - typedef std::map< LLUUID, std::vector<U8> > map_t; - map_t faces_per_texture; - for (U8 i = 0; i < te_count; i++) - { - if (!node->isTESelected(i)) continue; - - LLViewerTexture* img = node->getObject()->getTEImage(i); - LLUUID image_id = img->getID(); - faces_per_texture[image_id].push_back(i); - } - // Per-texture, dump which faces are using it. - map_t::iterator it; - for (it = faces_per_texture.begin(); it != faces_per_texture.end(); ++it) - { - LLUUID image_id = it->first; - U8 te = it->second[0]; - LLViewerTexture* img = node->getObject()->getTEImage(te); - S32 height = img->getHeight(); - S32 width = img->getWidth(); - S32 components = img->getComponents(); - msg = llformat("%dx%d %s on face ", - width, - height, - (components == 4 ? "alpha" : "opaque")); - for (U8 i = 0; i < it->second.size(); ++i) - { - msg.append( llformat("%d ", (S32)(it->second[i]))); - } - - LLSD args; - args["MESSAGE"] = msg; - LLNotificationsUtil::add("SystemMessage", args); - } - } -} - -void handle_test_male(void*) -{ - LLAppearanceMgr::instance().wearOutfitByName("Male Shape & Outfit"); - //gGestureList.requestResetFromServer( TRUE ); -} - -void handle_test_female(void*) -{ - LLAppearanceMgr::instance().wearOutfitByName("Female Shape & Outfit"); - //gGestureList.requestResetFromServer( FALSE ); -} - -void handle_toggle_pg(void*) -{ - gAgent.setTeen( !gAgent.isTeen() ); - - LLFloaterWorldMap::reloadIcons(NULL); - - llinfos << "PG status set to " << (S32)gAgent.isTeen() << llendl; -} - -void handle_dump_attachments(void*) -{ - if(!isAgentAvatarValid()) return; - - for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); - iter != gAgentAvatarp->mAttachmentPoints.end(); ) - { - LLVOAvatar::attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - S32 key = curiter->first; - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) - { - LLViewerObject *attached_object = (*attachment_iter); - BOOL visible = (attached_object != NULL && - attached_object->mDrawable.notNull() && - !attached_object->mDrawable->isRenderType(0)); - LLVector3 pos; - if (visible) pos = attached_object->mDrawable->getPosition(); - llinfos << "ATTACHMENT " << key << ": item_id=" << attached_object->getAttachmentItemID() - << (attached_object ? " present " : " absent ") - << (visible ? "visible " : "invisible ") - << " at " << pos - << " and " << (visible ? attached_object->getPosition() : LLVector3::zero) - << llendl; - } - } -} - - -// these are used in the gl menus to set control values, generically. -class LLToggleControl : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string control_name = userdata.asString(); - BOOL checked = gSavedSettings.getBOOL( control_name ); - gSavedSettings.setBOOL( control_name, !checked ); - return true; - } -}; - -class LLCheckControl : public view_listener_t -{ - bool handleEvent( const LLSD& userdata) - { - std::string callback_data = userdata.asString(); - bool new_value = gSavedSettings.getBOOL(callback_data); - return new_value; - } -}; - -// not so generic - -class LLAdvancedCheckRenderShadowOption: public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string control_name = userdata.asString(); - S32 current_shadow_level = gSavedSettings.getS32(control_name); - if (current_shadow_level == 0) // is off - { - return false; - } - else // is on - { - return true; - } - } -}; - -class LLAdvancedClickRenderShadowOption: public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string control_name = userdata.asString(); - S32 current_shadow_level = gSavedSettings.getS32(control_name); - if (current_shadow_level == 0) // upgrade to level 2 - { - gSavedSettings.setS32(control_name, 2); - } - else // downgrade to level 0 - { - gSavedSettings.setS32(control_name, 0); - } - return true; - } -}; - -void menu_toggle_attached_lights(void* user_data) -{ - LLPipeline::sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights"); -} - -void menu_toggle_attached_particles(void* user_data) -{ - LLPipeline::sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles"); -} - -class LLAdvancedHandleAttachedLightParticles: public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string control_name = userdata.asString(); - - // toggle the control - gSavedSettings.setBOOL(control_name, - !gSavedSettings.getBOOL(control_name)); - - // update internal flags - if (control_name == "RenderAttachedLights") - { - menu_toggle_attached_lights(NULL); - } - else if (control_name == "RenderAttachedParticles") - { - menu_toggle_attached_particles(NULL); - } - return true; - } -}; - -class LLSomethingSelected : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = !(LLSelectMgr::getInstance()->getSelection()->isEmpty()); - return new_value; - } -}; - -class LLSomethingSelectedNoHUD : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - bool new_value = !(selection->isEmpty()) && !(selection->getSelectType() == SELECT_TYPE_HUD); - return new_value; - } -}; - -static bool is_editable_selected() -{ - return (LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject() != NULL); -} - -class LLEditableSelected : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - return is_editable_selected(); - } -}; - -class LLEditableSelectedMono : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = false; - LLViewerRegion* region = gAgent.getRegion(); - if(region && gMenuHolder) - { - bool have_cap = (! region->getCapability("UpdateScriptTask").empty()); - new_value = is_editable_selected() && have_cap; - } - return new_value; - } -}; - -bool enable_object_take_copy() -{ - bool all_valid = false; - if (LLSelectMgr::getInstance()) - { - if (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) - { - all_valid = true; -#ifndef HACKED_GODLIKE_VIEWER -# ifdef TOGGLE_HACKED_GODLIKE_VIEWER - if (LLGridManager::getInstance()->isInProductionGrid() - || !gAgent.isGodlike()) -# endif - { - struct f : public LLSelectedObjectFunctor - { - virtual bool apply(LLViewerObject* obj) - { - return (!obj->permCopy() || obj->isAttachment()); - } - } func; - const bool firstonly = true; - bool any_invalid = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly); - all_valid = !any_invalid; - } -#endif // HACKED_GODLIKE_VIEWER - } - } - - return all_valid; -} - - -class LLHasAsset : public LLInventoryCollectFunctor -{ -public: - LLHasAsset(const LLUUID& id) : mAssetID(id), mHasAsset(FALSE) {} - virtual ~LLHasAsset() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); - BOOL hasAsset() const { return mHasAsset; } - -protected: - LLUUID mAssetID; - BOOL mHasAsset; -}; - -bool LLHasAsset::operator()(LLInventoryCategory* cat, - LLInventoryItem* item) -{ - if(item && item->getAssetUUID() == mAssetID) - { - mHasAsset = TRUE; - } - return FALSE; -} - -BOOL enable_save_into_inventory(void*) -{ - // *TODO: clean this up - // find the last root - LLSelectNode* last_node = NULL; - for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++) - { - last_node = *iter; - } - -#ifdef HACKED_GODLIKE_VIEWER - return TRUE; -#else -# ifdef TOGGLE_HACKED_GODLIKE_VIEWER - if (!LLGridManager::getInstance()->isInProductionGrid() - && gAgent.isGodlike()) - { - return TRUE; - } -# endif - // check all pre-req's for save into inventory. - if(last_node && last_node->mValid && !last_node->mItemID.isNull() - && (last_node->mPermissions->getOwner() == gAgent.getID()) - && (gInventory.getItem(last_node->mItemID) != NULL)) - { - LLViewerObject* obj = last_node->getObject(); - if( obj && !obj->isAttachment() ) - { - return TRUE; - } - } -#endif - return FALSE; -} - -class LLToolsEnableSaveToInventory : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = enable_save_into_inventory(NULL); - return new_value; - } -}; - -BOOL enable_save_into_task_inventory(void*) -{ - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if(node && (node->mValid) && (!node->mFromTaskID.isNull())) - { - // *TODO: check to see if the fromtaskid object exists. - LLViewerObject* obj = node->getObject(); - if( obj && !obj->isAttachment() ) - { - return TRUE; - } - } - return FALSE; -} - -class LLToolsEnableSaveToObjectInventory : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = enable_save_into_task_inventory(NULL); - return new_value; - } -}; - - -class LLViewEnableMouselook : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - // You can't go directly from customize avatar to mouselook. - // TODO: write code with appropriate dialogs to handle this transition. - bool new_value = (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && !gSavedSettings.getBOOL("FreezeTime")); - return new_value; - } -}; - -class LLToolsEnableToolNotPie : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = ( LLToolMgr::getInstance()->getBaseTool() != LLToolPie::getInstance() ); - return new_value; - } -}; - -class LLWorldEnableCreateLandmark : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - return !LLLandmarkActions::landmarkAlreadyExists(); - } -}; - -class LLWorldEnableSetHomeLocation : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = gAgent.isGodlike() || - (gAgent.getRegion() && gAgent.getRegion()->getAllowSetHome()); - return new_value; - } -}; - -class LLWorldEnableTeleportHome : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLViewerRegion* regionp = gAgent.getRegion(); - bool agent_on_prelude = (regionp && regionp->isPrelude()); - bool enable_teleport_home = gAgent.isGodlike() || !agent_on_prelude; - return enable_teleport_home; - } -}; - -BOOL enable_god_full(void*) -{ - return gAgent.getGodLevel() >= GOD_FULL; -} - -BOOL enable_god_liaison(void*) -{ - return gAgent.getGodLevel() >= GOD_LIAISON; -} - -bool is_god_customer_service() -{ - return gAgent.getGodLevel() >= GOD_CUSTOMER_SERVICE; -} - -BOOL enable_god_basic(void*) -{ - return gAgent.getGodLevel() > GOD_NOT; -} - - -void toggle_show_xui_names(void *) -{ - gSavedSettings.setBOOL("DebugShowXUINames", !gSavedSettings.getBOOL("DebugShowXUINames")); -} - -BOOL check_show_xui_names(void *) -{ - return gSavedSettings.getBOOL("DebugShowXUINames"); -} - -class LLToolsSelectOnlyMyObjects : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - BOOL cur_val = gSavedSettings.getBOOL("SelectOwnedOnly"); - - gSavedSettings.setBOOL("SelectOwnedOnly", ! cur_val ); - - return true; - } -}; - -class LLToolsSelectOnlyMovableObjects : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - BOOL cur_val = gSavedSettings.getBOOL("SelectMovableOnly"); - - gSavedSettings.setBOOL("SelectMovableOnly", ! cur_val ); - - return true; - } -}; - -class LLToolsSelectBySurrounding : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLSelectMgr::sRectSelectInclusive = !LLSelectMgr::sRectSelectInclusive; - - gSavedSettings.setBOOL("RectangleSelectInclusive", LLSelectMgr::sRectSelectInclusive); - return true; - } -}; - -class LLToolsShowHiddenSelection : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - // TomY TODO Merge these - LLSelectMgr::sRenderHiddenSelections = !LLSelectMgr::sRenderHiddenSelections; - - gSavedSettings.setBOOL("RenderHiddenSelections", LLSelectMgr::sRenderHiddenSelections); - return true; - } -}; - -class LLToolsShowSelectionLightRadius : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - // TomY TODO merge these - LLSelectMgr::sRenderLightRadius = !LLSelectMgr::sRenderLightRadius; - - gSavedSettings.setBOOL("RenderLightRadius", LLSelectMgr::sRenderLightRadius); - return true; - } -}; - -class LLToolsEditLinkedParts : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - BOOL select_individuals = !gSavedSettings.getBOOL("EditLinkedParts"); - gSavedSettings.setBOOL( "EditLinkedParts", select_individuals ); - if (select_individuals) - { - LLSelectMgr::getInstance()->demoteSelectionToIndividuals(); - } - else - { - LLSelectMgr::getInstance()->promoteSelectionToRoot(); - } - return true; - } -}; - -void reload_vertex_shader(void *) -{ - //THIS WOULD BE AN AWESOME PLACE TO RELOAD SHADERS... just a thought - DaveP -} - -void handle_dump_avatar_local_textures(void*) -{ - gAgentAvatarp->dumpLocalTextures(); -} - -void handle_dump_timers() -{ - LLFastTimer::dumpCurTimes(); -} - -void handle_debug_avatar_textures(void*) -{ - LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (objectp) - { - LLFloaterReg::showInstance( "avatar_textures", LLSD(objectp->getID()) ); - } -} - -void handle_grab_baked_texture(void* data) -{ - EBakedTextureIndex baked_tex_index = (EBakedTextureIndex)((intptr_t)data); - if (!isAgentAvatarValid()) return; - - const LLUUID& asset_id = gAgentAvatarp->grabBakedTexture(baked_tex_index); - LL_INFOS("texture") << "Adding baked texture " << asset_id << " to inventory." << llendl; - LLAssetType::EType asset_type = LLAssetType::AT_TEXTURE; - LLInventoryType::EType inv_type = LLInventoryType::IT_TEXTURE; - const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(asset_type)); - if(folder_id.notNull()) - { - std::string name; - name = "Baked " + LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_tex_index)->mNameCapitalized + " Texture"; - - LLUUID item_id; - item_id.generate(); - LLPermissions perm; - perm.init(gAgentID, - gAgentID, - LLUUID::null, - LLUUID::null); - U32 next_owner_perm = PERM_MOVE | PERM_TRANSFER; - perm.initMasks(PERM_ALL, - PERM_ALL, - PERM_NONE, - PERM_NONE, - next_owner_perm); - time_t creation_date_now = time_corrected(); - LLPointer<LLViewerInventoryItem> item - = new LLViewerInventoryItem(item_id, - folder_id, - perm, - asset_id, - asset_type, - inv_type, - name, - LLStringUtil::null, - LLSaleInfo::DEFAULT, - LLInventoryItemFlags::II_FLAGS_NONE, - creation_date_now); - - item->updateServer(TRUE); - gInventory.updateItem(item); - gInventory.notifyObservers(); - - // Show the preview panel for textures to let - // user know that the image is now in inventory. - LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); - if(active_panel) - { - LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus(); - - active_panel->setSelection(item_id, TAKE_FOCUS_NO); - active_panel->openSelected(); - //LLFloaterInventory::dumpSelectionInformation((void*)view); - // restore keyboard focus - gFocusMgr.setKeyboardFocus(focus_ctrl); - } - } - else - { - llwarns << "Can't find a folder to put it in" << llendl; - } -} - -BOOL enable_grab_baked_texture(void* data) -{ - EBakedTextureIndex index = (EBakedTextureIndex)((intptr_t)data); - if (isAgentAvatarValid()) - { - return gAgentAvatarp->canGrabBakedTexture(index); - } - return FALSE; -} - -// Returns a pointer to the avatar give the UUID of the avatar OR of an attachment the avatar is wearing. -// Returns NULL on failure. -LLVOAvatar* find_avatar_from_object( LLViewerObject* object ) -{ - if (object) - { - if( object->isAttachment() ) - { - do - { - object = (LLViewerObject*) object->getParent(); - } - while( object && !object->isAvatar() ); - } - else if( !object->isAvatar() ) - { - object = NULL; - } - } - - return (LLVOAvatar*) object; -} - - -// Returns a pointer to the avatar give the UUID of the avatar OR of an attachment the avatar is wearing. -// Returns NULL on failure. -LLVOAvatar* find_avatar_from_object( const LLUUID& object_id ) -{ - return find_avatar_from_object( gObjectList.findObject(object_id) ); -} - - -void handle_disconnect_viewer(void *) -{ - LLAppViewer::instance()->forceDisconnect(LLTrans::getString("TestingDisconnect")); -} - -void force_error_breakpoint(void *) -{ - LLAppViewer::instance()->forceErrorBreakpoint(); -} - -void force_error_llerror(void *) -{ - LLAppViewer::instance()->forceErrorLLError(); -} - -void force_error_bad_memory_access(void *) -{ - LLAppViewer::instance()->forceErrorBadMemoryAccess(); -} - -void force_error_infinite_loop(void *) -{ - LLAppViewer::instance()->forceErrorInfiniteLoop(); -} - -void force_error_software_exception(void *) -{ - LLAppViewer::instance()->forceErrorSoftwareException(); -} - -void force_error_driver_crash(void *) -{ - LLAppViewer::instance()->forceErrorDriverCrash(); -} - -class LLToolsUseSelectionForGrid : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLSelectMgr::getInstance()->clearGridObjects(); - struct f : public LLSelectedObjectFunctor - { - virtual bool apply(LLViewerObject* objectp) - { - LLSelectMgr::getInstance()->addGridObject(objectp); - return true; - } - } func; - LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func); - LLSelectMgr::getInstance()->setGridMode(GRID_MODE_REF_OBJECT); - if (gFloaterTools) - { - gFloaterTools->mComboGridMode->setCurrentByIndex((S32)GRID_MODE_REF_OBJECT); - } - return true; - } -}; - -void handle_test_load_url(void*) -{ - LLWeb::loadURL(""); - LLWeb::loadURL("hacker://www.google.com/"); - LLWeb::loadURL("http"); - LLWeb::loadURL("http://www.google.com/"); -} - -// -// LLViewerMenuHolderGL -// -static LLDefaultChildRegistry::Register<LLViewerMenuHolderGL> r("menu_holder"); - -LLViewerMenuHolderGL::LLViewerMenuHolderGL(const LLViewerMenuHolderGL::Params& p) -: LLMenuHolderGL(p) -{} - -BOOL LLViewerMenuHolderGL::hideMenus() -{ - BOOL handled = LLMenuHolderGL::hideMenus(); - - // drop pie menu selection - mParcelSelection = NULL; - mObjectSelection = NULL; - - if (gMenuBarView) - { - gMenuBarView->clearHoverItem(); - gMenuBarView->resetMenuTrigger(); - } - - return handled; -} - -void LLViewerMenuHolderGL::setParcelSelection(LLSafeHandle<LLParcelSelection> selection) -{ - mParcelSelection = selection; -} - -void LLViewerMenuHolderGL::setObjectSelection(LLSafeHandle<LLObjectSelection> selection) -{ - mObjectSelection = selection; -} - - -const LLRect LLViewerMenuHolderGL::getMenuRect() const -{ - return LLRect(0, getRect().getHeight() - MENU_BAR_HEIGHT, getRect().getWidth(), STATUS_BAR_HEIGHT); -} - -void handle_web_browser_test(const LLSD& param) -{ - std::string url = param.asString(); - if (url.empty()) - { - url = "about:blank"; - } - LLWeb::loadURLInternal(url); -} - -void handle_web_content_test(const LLSD& param) -{ - std::string url = param.asString(); - LLWeb::loadWebURLInternal(url); -} - -void handle_buy_currency_test(void*) -{ - std::string url = - "http://sarahd-sl-13041.webdev.lindenlab.com/app/lindex/index.php?agent_id=[AGENT_ID]&secure_session_id=[SESSION_ID]&lang=[LANGUAGE]"; - - LLStringUtil::format_map_t replace; - replace["[AGENT_ID]"] = gAgent.getID().asString(); - replace["[SESSION_ID]"] = gAgent.getSecureSessionID().asString(); - replace["[LANGUAGE]"] = LLUI::getLanguage(); - LLStringUtil::format(url, replace); - - llinfos << "buy currency url " << url << llendl; - - LLFloaterReg::showInstance("buy_currency_html", LLSD(url)); -} - -void handle_rebake_textures(void*) -{ - if (!isAgentAvatarValid()) return; - - // Slam pending upload count to "unstick" things - bool slam_for_debug = true; - gAgentAvatarp->forceBakeAllTextures(slam_for_debug); -} - -void toggle_visibility(void* user_data) -{ - LLView* viewp = (LLView*)user_data; - viewp->setVisible(!viewp->getVisible()); -} - -BOOL get_visibility(void* user_data) -{ - LLView* viewp = (LLView*)user_data; - return viewp->getVisible(); -} - -// TomY TODO: Get rid of these? -class LLViewShowHoverTips : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - gSavedSettings.setBOOL("ShowHoverTips", !gSavedSettings.getBOOL("ShowHoverTips")); - return true; - } -}; - -class LLViewCheckShowHoverTips : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = gSavedSettings.getBOOL("ShowHoverTips"); - return new_value; - } -}; - -// TomY TODO: Get rid of these? -class LLViewHighlightTransparent : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha; - return true; - } -}; - -class LLViewCheckHighlightTransparent : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLDrawPoolAlpha::sShowDebugAlpha; - return new_value; - } -}; - -class LLViewBeaconWidth : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string width = userdata.asString(); - if(width == "1") - { - gSavedSettings.setS32("DebugBeaconLineWidth", 1); - } - else if(width == "4") - { - gSavedSettings.setS32("DebugBeaconLineWidth", 4); - } - else if(width == "16") - { - gSavedSettings.setS32("DebugBeaconLineWidth", 16); - } - else if(width == "32") - { - gSavedSettings.setS32("DebugBeaconLineWidth", 32); - } - - return true; - } -}; - - -class LLViewToggleBeacon : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string beacon = userdata.asString(); - if (beacon == "scriptsbeacon") - { - LLPipeline::toggleRenderScriptedBeacons(NULL); - gSavedSettings.setBOOL( "scriptsbeacon", LLPipeline::getRenderScriptedBeacons(NULL) ); - // toggle the other one off if it's on - if (LLPipeline::getRenderScriptedBeacons(NULL) && LLPipeline::getRenderScriptedTouchBeacons(NULL)) - { - LLPipeline::toggleRenderScriptedTouchBeacons(NULL); - gSavedSettings.setBOOL( "scripttouchbeacon", LLPipeline::getRenderScriptedTouchBeacons(NULL) ); - } - } - else if (beacon == "physicalbeacon") - { - LLPipeline::toggleRenderPhysicalBeacons(NULL); - gSavedSettings.setBOOL( "physicalbeacon", LLPipeline::getRenderPhysicalBeacons(NULL) ); - } - else if (beacon == "soundsbeacon") - { - LLPipeline::toggleRenderSoundBeacons(NULL); - gSavedSettings.setBOOL( "soundsbeacon", LLPipeline::getRenderSoundBeacons(NULL) ); - } - else if (beacon == "particlesbeacon") - { - LLPipeline::toggleRenderParticleBeacons(NULL); - gSavedSettings.setBOOL( "particlesbeacon", LLPipeline::getRenderParticleBeacons(NULL) ); - } - else if (beacon == "scripttouchbeacon") - { - LLPipeline::toggleRenderScriptedTouchBeacons(NULL); - gSavedSettings.setBOOL( "scripttouchbeacon", LLPipeline::getRenderScriptedTouchBeacons(NULL) ); - // toggle the other one off if it's on - if (LLPipeline::getRenderScriptedBeacons(NULL) && LLPipeline::getRenderScriptedTouchBeacons(NULL)) - { - LLPipeline::toggleRenderScriptedBeacons(NULL); - gSavedSettings.setBOOL( "scriptsbeacon", LLPipeline::getRenderScriptedBeacons(NULL) ); - } - } - else if (beacon == "renderbeacons") - { - LLPipeline::toggleRenderBeacons(NULL); - gSavedSettings.setBOOL( "renderbeacons", LLPipeline::getRenderBeacons(NULL) ); - // toggle the other one on if it's not - if (!LLPipeline::getRenderBeacons(NULL) && !LLPipeline::getRenderHighlights(NULL)) - { - LLPipeline::toggleRenderHighlights(NULL); - gSavedSettings.setBOOL( "renderhighlights", LLPipeline::getRenderHighlights(NULL) ); - } - } - else if (beacon == "renderhighlights") - { - LLPipeline::toggleRenderHighlights(NULL); - gSavedSettings.setBOOL( "renderhighlights", LLPipeline::getRenderHighlights(NULL) ); - // toggle the other one on if it's not - if (!LLPipeline::getRenderBeacons(NULL) && !LLPipeline::getRenderHighlights(NULL)) - { - LLPipeline::toggleRenderBeacons(NULL); - gSavedSettings.setBOOL( "renderbeacons", LLPipeline::getRenderBeacons(NULL) ); - } - } - - return true; - } -}; - -class LLViewCheckBeaconEnabled : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string beacon = userdata.asString(); - bool new_value = false; - if (beacon == "scriptsbeacon") - { - new_value = gSavedSettings.getBOOL( "scriptsbeacon"); - LLPipeline::setRenderScriptedBeacons(new_value); - } - else if (beacon == "physicalbeacon") - { - new_value = gSavedSettings.getBOOL( "physicalbeacon"); - LLPipeline::setRenderPhysicalBeacons(new_value); - } - else if (beacon == "soundsbeacon") - { - new_value = gSavedSettings.getBOOL( "soundsbeacon"); - LLPipeline::setRenderSoundBeacons(new_value); - } - else if (beacon == "particlesbeacon") - { - new_value = gSavedSettings.getBOOL( "particlesbeacon"); - LLPipeline::setRenderParticleBeacons(new_value); - } - else if (beacon == "scripttouchbeacon") - { - new_value = gSavedSettings.getBOOL( "scripttouchbeacon"); - LLPipeline::setRenderScriptedTouchBeacons(new_value); - } - else if (beacon == "renderbeacons") - { - new_value = gSavedSettings.getBOOL( "renderbeacons"); - LLPipeline::setRenderBeacons(new_value); - } - else if (beacon == "renderhighlights") - { - new_value = gSavedSettings.getBOOL( "renderhighlights"); - LLPipeline::setRenderHighlights(new_value); - } - return new_value; - } -}; - -class LLViewToggleRenderType : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string type = userdata.asString(); - if (type == "hideparticles") - { - LLPipeline::toggleRenderType(LLPipeline::RENDER_TYPE_PARTICLES); - } - return true; - } -}; - -class LLViewCheckRenderType : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string type = userdata.asString(); - bool new_value = false; - if (type == "hideparticles") - { - new_value = LLPipeline::toggleRenderTypeControlNegated((void *)LLPipeline::RENDER_TYPE_PARTICLES); - } - return new_value; - } -}; - -class LLViewShowHUDAttachments : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLPipeline::sShowHUDAttachments = !LLPipeline::sShowHUDAttachments; - return true; - } -}; - -class LLViewCheckHUDAttachments : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool new_value = LLPipeline::sShowHUDAttachments; - return new_value; - } -}; - -class LLEditEnableTakeOff : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string clothing = userdata.asString(); - LLWearableType::EType type = LLWearableType::typeNameToType(clothing); - if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT) - return LLAgentWearables::selfHasWearable(type); - return false; - } -}; - -class LLEditTakeOff : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string clothing = userdata.asString(); - if (clothing == "all") - LLWearableBridge::removeAllClothesFromAvatar(); - else - { - LLWearableType::EType type = LLWearableType::typeNameToType(clothing); - if (type >= LLWearableType::WT_SHAPE - && type < LLWearableType::WT_COUNT - && (gAgentWearables.getWearableCount(type) > 0)) - { - // MULTI-WEARABLES: assuming user wanted to remove top shirt. - U32 wearable_index = gAgentWearables.getWearableCount(type) - 1; - LLViewerInventoryItem *item = dynamic_cast<LLViewerInventoryItem*>(gAgentWearables.getWearableInventoryItem(type,wearable_index)); - LLWearableBridge::removeItemFromAvatar(item); - } - - } - return true; - } -}; - -class LLToolsSelectTool : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string tool_name = userdata.asString(); - if (tool_name == "focus") - { - LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(1); - } - else if (tool_name == "move") - { - LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(2); - } - else if (tool_name == "edit") - { - LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(3); - } - else if (tool_name == "create") - { - LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(4); - } - else if (tool_name == "land") - { - LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(5); - } - return true; - } -}; - -/// WINDLIGHT callbacks -class LLWorldEnvSettings : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - std::string tod = userdata.asString(); - LLVector3 sun_direction; - - if (tod == "editor") - { - // if not there or is hidden, show it - LLFloaterReg::toggleInstance("env_settings"); - return true; - } - - if (tod == "sunrise") - { - // set the value, turn off animation - LLWLParamManager::instance()->mAnimator.setDayTime(0.25); - LLWLParamManager::instance()->mAnimator.mIsRunning = false; - LLWLParamManager::instance()->mAnimator.mUseLindenTime = false; - - // then call update once - LLWLParamManager::instance()->mAnimator.update( - LLWLParamManager::instance()->mCurParams); - } - else if (tod == "noon") - { - // set the value, turn off animation - LLWLParamManager::instance()->mAnimator.setDayTime(0.567); - LLWLParamManager::instance()->mAnimator.mIsRunning = false; - LLWLParamManager::instance()->mAnimator.mUseLindenTime = false; - - // then call update once - LLWLParamManager::instance()->mAnimator.update( - LLWLParamManager::instance()->mCurParams); - } - else if (tod == "sunset") - { - // set the value, turn off animation - LLWLParamManager::instance()->mAnimator.setDayTime(0.75); - LLWLParamManager::instance()->mAnimator.mIsRunning = false; - LLWLParamManager::instance()->mAnimator.mUseLindenTime = false; - - // then call update once - LLWLParamManager::instance()->mAnimator.update( - LLWLParamManager::instance()->mCurParams); - } - else if (tod == "midnight") - { - // set the value, turn off animation - LLWLParamManager::instance()->mAnimator.setDayTime(0.0); - LLWLParamManager::instance()->mAnimator.mIsRunning = false; - LLWLParamManager::instance()->mAnimator.mUseLindenTime = false; - - // then call update once - LLWLParamManager::instance()->mAnimator.update( - LLWLParamManager::instance()->mCurParams); - } - else - { - LLWLParamManager::instance()->mAnimator.mIsRunning = true; - LLWLParamManager::instance()->mAnimator.mUseLindenTime = true; - } - return true; - } -}; - -/// Water Menu callbacks -class LLWorldWaterSettings : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLFloaterReg::toggleInstance("env_water"); - return true; - } -}; - -/// Post-Process callbacks -class LLWorldPostProcess : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLFloaterReg::showInstance("env_post_process"); - return true; - } -}; - -/// Day Cycle callbacks -class LLWorldDayCycle : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLFloaterReg::showInstance("env_day_cycle"); - return true; - } -}; - -class LLWorldToggleMovementControls : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLBottomTray::getInstance()->toggleMovementControls(); - return true; - } -}; - -class LLWorldToggleCameraControls : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - LLBottomTray::getInstance()->toggleCameraControls(); - return true; - } -}; - -void handle_flush_name_caches() -{ - // Toggle display names on and off to flush - bool use_display_names = LLAvatarNameCache::useDisplayNames(); - LLAvatarNameCache::setUseDisplayNames(!use_display_names); - LLAvatarNameCache::setUseDisplayNames(use_display_names); - - if (gCacheName) gCacheName->clear(); -} - -class LLUploadCostCalculator : public view_listener_t -{ - std::string mCostStr; - - bool handleEvent(const LLSD& userdata) - { - std::string menu_name = userdata.asString(); - gMenuHolder->childSetLabelArg(menu_name, "[COST]", mCostStr); - - return true; - } - - void calculateCost(); - -public: - LLUploadCostCalculator() - { - calculateCost(); - } -}; - -class LLToggleUIHints : public view_listener_t -{ - bool handleEvent(const LLSD& userdata) - { - bool ui_hints_enabled = gSavedSettings.getBOOL("EnableUIHints"); - // toggle - ui_hints_enabled = !ui_hints_enabled; - gSavedSettings.setBOOL("EnableUIHints", ui_hints_enabled); - return true; - } -}; - -void LLUploadCostCalculator::calculateCost() -{ - S32 upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); - - // getPriceUpload() returns -1 if no data available yet. - if(upload_cost >= 0) - { - mCostStr = llformat("%d", upload_cost); - } - else - { - mCostStr = llformat("%d", gSavedSettings.getU32("DefaultUploadCost")); - } -} - -void show_navbar_context_menu(LLView* ctrl, S32 x, S32 y) -{ - static LLMenuGL* show_navbar_context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_hide_navbar.xml", - gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - if(gMenuHolder->hasVisibleMenu()) - { - gMenuHolder->hideMenus(); - } - show_navbar_context_menu->buildDrawLabels(); - show_navbar_context_menu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(ctrl, show_navbar_context_menu, x, y); -} - -void show_topinfobar_context_menu(LLView* ctrl, S32 x, S32 y) -{ - static LLMenuGL* show_topbarinfo_context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_topinfobar.xml", - gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - - LLMenuItemGL* landmark_item = show_topbarinfo_context_menu->getChild<LLMenuItemGL>("Landmark"); - if (!LLLandmarkActions::landmarkAlreadyExists()) - { - landmark_item->setLabel(LLTrans::getString("AddLandmarkNavBarMenu")); - } - else - { - landmark_item->setLabel(LLTrans::getString("EditLandmarkNavBarMenu")); - } - - if(gMenuHolder->hasVisibleMenu()) - { - gMenuHolder->hideMenus(); - } - - show_topbarinfo_context_menu->buildDrawLabels(); - show_topbarinfo_context_menu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(ctrl, show_topbarinfo_context_menu, x, y); -} - -void initialize_edit_menu() -{ - view_listener_t::addMenu(new LLEditUndo(), "Edit.Undo"); - view_listener_t::addMenu(new LLEditRedo(), "Edit.Redo"); - view_listener_t::addMenu(new LLEditCut(), "Edit.Cut"); - view_listener_t::addMenu(new LLEditCopy(), "Edit.Copy"); - view_listener_t::addMenu(new LLEditPaste(), "Edit.Paste"); - view_listener_t::addMenu(new LLEditDelete(), "Edit.Delete"); - view_listener_t::addMenu(new LLEditSelectAll(), "Edit.SelectAll"); - view_listener_t::addMenu(new LLEditDeselect(), "Edit.Deselect"); - view_listener_t::addMenu(new LLEditDuplicate(), "Edit.Duplicate"); - view_listener_t::addMenu(new LLEditTakeOff(), "Edit.TakeOff"); - view_listener_t::addMenu(new LLEditEnableUndo(), "Edit.EnableUndo"); - view_listener_t::addMenu(new LLEditEnableRedo(), "Edit.EnableRedo"); - view_listener_t::addMenu(new LLEditEnableCut(), "Edit.EnableCut"); - view_listener_t::addMenu(new LLEditEnableCopy(), "Edit.EnableCopy"); - view_listener_t::addMenu(new LLEditEnablePaste(), "Edit.EnablePaste"); - view_listener_t::addMenu(new LLEditEnableDelete(), "Edit.EnableDelete"); - view_listener_t::addMenu(new LLEditEnableSelectAll(), "Edit.EnableSelectAll"); - view_listener_t::addMenu(new LLEditEnableDeselect(), "Edit.EnableDeselect"); - view_listener_t::addMenu(new LLEditEnableDuplicate(), "Edit.EnableDuplicate"); - -} - -void initialize_menus() -{ - // A parameterized event handler used as ctrl-8/9/0 zoom controls below. - class LLZoomer : public view_listener_t - { - public: - // The "mult" parameter says whether "val" is a multiplier or used to set the value. - LLZoomer(F32 val, bool mult=true) : mVal(val), mMult(mult) {} - bool handleEvent(const LLSD& userdata) - { - F32 new_fov_rad = mMult ? LLViewerCamera::getInstance()->getDefaultFOV() * mVal : mVal; - LLViewerCamera::getInstance()->setDefaultFOV(new_fov_rad); - gSavedSettings.setF32("CameraAngle", LLViewerCamera::getInstance()->getView()); // setView may have clamped it. - return true; - } - private: - F32 mVal; - bool mMult; - }; - - LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar(); - LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar(); - - // Generic enable and visible - // Don't prepend MenuName.Foo because these can be used in any menu. - enable.add("IsGodCustomerService", boost::bind(&is_god_customer_service)); - - view_listener_t::addEnable(new LLUploadCostCalculator(), "Upload.CalculateCosts"); - - // Agent - commit.add("Agent.toggleFlying", boost::bind(&LLAgent::toggleFlying)); - enable.add("Agent.enableFlying", boost::bind(&LLAgent::enableFlying)); - - // File menu - init_menu_file(); - - view_listener_t::addMenu(new LLEditEnableTakeOff(), "Edit.EnableTakeOff"); - view_listener_t::addMenu(new LLEditEnableCustomizeAvatar(), "Edit.EnableCustomizeAvatar"); - view_listener_t::addMenu(new LLEnableEditShape(), "Edit.EnableEditShape"); - commit.add("CustomizeAvatar", boost::bind(&handle_customize_avatar)); - commit.add("EditOutfit", boost::bind(&handle_edit_outfit)); - commit.add("EditShape", boost::bind(&handle_edit_shape)); - - // View menu - view_listener_t::addMenu(new LLViewMouselook(), "View.Mouselook"); - view_listener_t::addMenu(new LLViewJoystickFlycam(), "View.JoystickFlycam"); - view_listener_t::addMenu(new LLViewResetView(), "View.ResetView"); - view_listener_t::addMenu(new LLViewLookAtLastChatter(), "View.LookAtLastChatter"); - view_listener_t::addMenu(new LLViewShowHoverTips(), "View.ShowHoverTips"); - view_listener_t::addMenu(new LLViewHighlightTransparent(), "View.HighlightTransparent"); - view_listener_t::addMenu(new LLViewToggleRenderType(), "View.ToggleRenderType"); - view_listener_t::addMenu(new LLViewShowHUDAttachments(), "View.ShowHUDAttachments"); - view_listener_t::addMenu(new LLZoomer(1.2f), "View.ZoomOut"); - view_listener_t::addMenu(new LLZoomer(1/1.2f), "View.ZoomIn"); - view_listener_t::addMenu(new LLZoomer(DEFAULT_FIELD_OF_VIEW, false), "View.ZoomDefault"); - view_listener_t::addMenu(new LLViewDefaultUISize(), "View.DefaultUISize"); - - view_listener_t::addMenu(new LLViewEnableMouselook(), "View.EnableMouselook"); - view_listener_t::addMenu(new LLViewEnableJoystickFlycam(), "View.EnableJoystickFlycam"); - view_listener_t::addMenu(new LLViewEnableLastChatter(), "View.EnableLastChatter"); - - view_listener_t::addMenu(new LLViewCheckJoystickFlycam(), "View.CheckJoystickFlycam"); - view_listener_t::addMenu(new LLViewCheckShowHoverTips(), "View.CheckShowHoverTips"); - view_listener_t::addMenu(new LLViewCheckHighlightTransparent(), "View.CheckHighlightTransparent"); - view_listener_t::addMenu(new LLViewCheckRenderType(), "View.CheckRenderType"); - view_listener_t::addMenu(new LLViewCheckHUDAttachments(), "View.CheckHUDAttachments"); - - // Me > Movement - view_listener_t::addMenu(new LLAdvancedAgentFlyingInfo(), "Agent.getFlying"); - - // World menu - commit.add("World.Chat", boost::bind(&handle_chat, (void*)NULL)); - view_listener_t::addMenu(new LLWorldAlwaysRun(), "World.AlwaysRun"); - view_listener_t::addMenu(new LLWorldCreateLandmark(), "World.CreateLandmark"); - view_listener_t::addMenu(new LLWorldPlaceProfile(), "World.PlaceProfile"); - view_listener_t::addMenu(new LLWorldSetHomeLocation(), "World.SetHomeLocation"); - view_listener_t::addMenu(new LLWorldTeleportHome(), "World.TeleportHome"); - view_listener_t::addMenu(new LLWorldSetAway(), "World.SetAway"); - view_listener_t::addMenu(new LLWorldSetBusy(), "World.SetBusy"); - - view_listener_t::addMenu(new LLWorldEnableCreateLandmark(), "World.EnableCreateLandmark"); - view_listener_t::addMenu(new LLWorldEnableSetHomeLocation(), "World.EnableSetHomeLocation"); - view_listener_t::addMenu(new LLWorldEnableTeleportHome(), "World.EnableTeleportHome"); - view_listener_t::addMenu(new LLWorldEnableBuyLand(), "World.EnableBuyLand"); - - view_listener_t::addMenu(new LLWorldCheckAlwaysRun(), "World.CheckAlwaysRun"); - - view_listener_t::addMenu(new LLWorldEnvSettings(), "World.EnvSettings"); - view_listener_t::addMenu(new LLWorldWaterSettings(), "World.WaterSettings"); - view_listener_t::addMenu(new LLWorldPostProcess(), "World.PostProcess"); - view_listener_t::addMenu(new LLWorldDayCycle(), "World.DayCycle"); - - view_listener_t::addMenu(new LLWorldToggleMovementControls(), "World.Toggle.MovementControls"); - view_listener_t::addMenu(new LLWorldToggleCameraControls(), "World.Toggle.CameraControls"); - - // Tools menu - view_listener_t::addMenu(new LLToolsSelectTool(), "Tools.SelectTool"); - view_listener_t::addMenu(new LLToolsSelectOnlyMyObjects(), "Tools.SelectOnlyMyObjects"); - view_listener_t::addMenu(new LLToolsSelectOnlyMovableObjects(), "Tools.SelectOnlyMovableObjects"); - view_listener_t::addMenu(new LLToolsSelectBySurrounding(), "Tools.SelectBySurrounding"); - view_listener_t::addMenu(new LLToolsShowHiddenSelection(), "Tools.ShowHiddenSelection"); - view_listener_t::addMenu(new LLToolsShowSelectionLightRadius(), "Tools.ShowSelectionLightRadius"); - view_listener_t::addMenu(new LLToolsEditLinkedParts(), "Tools.EditLinkedParts"); - view_listener_t::addMenu(new LLToolsSnapObjectXY(), "Tools.SnapObjectXY"); - view_listener_t::addMenu(new LLToolsUseSelectionForGrid(), "Tools.UseSelectionForGrid"); - view_listener_t::addMenu(new LLToolsSelectNextPart(), "Tools.SelectNextPart"); - commit.add("Tools.Link", boost::bind(&LLSelectMgr::linkObjects, LLSelectMgr::getInstance())); - commit.add("Tools.Unlink", boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance())); - view_listener_t::addMenu(new LLToolsStopAllAnimations(), "Tools.StopAllAnimations"); - view_listener_t::addMenu(new LLToolsReleaseKeys(), "Tools.ReleaseKeys"); - view_listener_t::addMenu(new LLToolsEnableReleaseKeys(), "Tools.EnableReleaseKeys"); - commit.add("Tools.LookAtSelection", boost::bind(&handle_look_at_selection, _2)); - commit.add("Tools.BuyOrTake", boost::bind(&handle_buy_or_take)); - commit.add("Tools.TakeCopy", boost::bind(&handle_take_copy)); - view_listener_t::addMenu(new LLToolsSaveToInventory(), "Tools.SaveToInventory"); - view_listener_t::addMenu(new LLToolsSaveToObjectInventory(), "Tools.SaveToObjectInventory"); - view_listener_t::addMenu(new LLToolsSelectedScriptAction(), "Tools.SelectedScriptAction"); - - view_listener_t::addMenu(new LLToolsEnableToolNotPie(), "Tools.EnableToolNotPie"); - view_listener_t::addMenu(new LLToolsEnableSelectNextPart(), "Tools.EnableSelectNextPart"); - enable.add("Tools.EnableLink", boost::bind(&LLSelectMgr::enableLinkObjects, LLSelectMgr::getInstance())); - enable.add("Tools.EnableUnlink", boost::bind(&LLSelectMgr::enableUnlinkObjects, LLSelectMgr::getInstance())); - view_listener_t::addMenu(new LLToolsEnableBuyOrTake(), "Tools.EnableBuyOrTake"); - enable.add("Tools.EnableTakeCopy", boost::bind(&enable_object_take_copy)); - enable.add("Tools.VisibleBuyObject", boost::bind(&tools_visible_buy_object)); - enable.add("Tools.VisibleTakeObject", boost::bind(&tools_visible_take_object)); - view_listener_t::addMenu(new LLToolsEnableSaveToInventory(), "Tools.EnableSaveToInventory"); - view_listener_t::addMenu(new LLToolsEnableSaveToObjectInventory(), "Tools.EnableSaveToObjectInventory"); - - // Help menu - // most items use the ShowFloater method - - // Advanced menu - view_listener_t::addMenu(new LLAdvancedToggleConsole(), "Advanced.ToggleConsole"); - view_listener_t::addMenu(new LLAdvancedCheckConsole(), "Advanced.CheckConsole"); - view_listener_t::addMenu(new LLAdvancedDumpInfoToConsole(), "Advanced.DumpInfoToConsole"); - - // Advanced > HUD Info - view_listener_t::addMenu(new LLAdvancedToggleHUDInfo(), "Advanced.ToggleHUDInfo"); - view_listener_t::addMenu(new LLAdvancedCheckHUDInfo(), "Advanced.CheckHUDInfo"); - - // Advanced Other Settings - view_listener_t::addMenu(new LLAdvancedClearGroupCache(), "Advanced.ClearGroupCache"); - - // Advanced > Render > Types - view_listener_t::addMenu(new LLAdvancedToggleRenderType(), "Advanced.ToggleRenderType"); - view_listener_t::addMenu(new LLAdvancedCheckRenderType(), "Advanced.CheckRenderType"); - - //// Advanced > Render > Features - view_listener_t::addMenu(new LLAdvancedToggleFeature(), "Advanced.ToggleFeature"); - view_listener_t::addMenu(new LLAdvancedCheckFeature(), "Advanced.CheckFeature"); - // Advanced > Render > Info Displays - view_listener_t::addMenu(new LLAdvancedToggleInfoDisplay(), "Advanced.ToggleInfoDisplay"); - view_listener_t::addMenu(new LLAdvancedCheckInfoDisplay(), "Advanced.CheckInfoDisplay"); - view_listener_t::addMenu(new LLAdvancedSelectedTextureInfo(), "Advanced.SelectedTextureInfo"); - view_listener_t::addMenu(new LLAdvancedToggleWireframe(), "Advanced.ToggleWireframe"); - view_listener_t::addMenu(new LLAdvancedCheckWireframe(), "Advanced.CheckWireframe"); - // Develop > Render - view_listener_t::addMenu(new LLAdvancedToggleTextureAtlas(), "Advanced.ToggleTextureAtlas"); - view_listener_t::addMenu(new LLAdvancedCheckTextureAtlas(), "Advanced.CheckTextureAtlas"); - view_listener_t::addMenu(new LLAdvancedEnableObjectObjectOcclusion(), "Advanced.EnableObjectObjectOcclusion"); - view_listener_t::addMenu(new LLAdvancedEnableRenderFBO(), "Advanced.EnableRenderFBO"); - view_listener_t::addMenu(new LLAdvancedEnableRenderDeferred(), "Advanced.EnableRenderDeferred"); - view_listener_t::addMenu(new LLAdvancedEnableRenderDeferredOptions(), "Advanced.EnableRenderDeferredOptions"); - view_listener_t::addMenu(new LLAdvancedToggleRandomizeFramerate(), "Advanced.ToggleRandomizeFramerate"); - view_listener_t::addMenu(new LLAdvancedCheckRandomizeFramerate(), "Advanced.CheckRandomizeFramerate"); - view_listener_t::addMenu(new LLAdvancedTogglePeriodicSlowFrame(), "Advanced.TogglePeriodicSlowFrame"); - view_listener_t::addMenu(new LLAdvancedCheckPeriodicSlowFrame(), "Advanced.CheckPeriodicSlowFrame"); - view_listener_t::addMenu(new LLAdvancedVectorizePerfTest(), "Advanced.VectorizePerfTest"); - view_listener_t::addMenu(new LLAdvancedToggleFrameTest(), "Advanced.ToggleFrameTest"); - view_listener_t::addMenu(new LLAdvancedCheckFrameTest(), "Advanced.CheckFrameTest"); - view_listener_t::addMenu(new LLAdvancedHandleAttachedLightParticles(), "Advanced.HandleAttachedLightParticles"); - view_listener_t::addMenu(new LLAdvancedCheckRenderShadowOption(), "Advanced.CheckRenderShadowOption"); - view_listener_t::addMenu(new LLAdvancedClickRenderShadowOption(), "Advanced.ClickRenderShadowOption"); - - - #ifdef TOGGLE_HACKED_GODLIKE_VIEWER - view_listener_t::addMenu(new LLAdvancedHandleToggleHackedGodmode(), "Advanced.HandleToggleHackedGodmode"); - view_listener_t::addMenu(new LLAdvancedCheckToggleHackedGodmode(), "Advanced.CheckToggleHackedGodmode"); - view_listener_t::addMenu(new LLAdvancedEnableToggleHackedGodmode(), "Advanced.EnableToggleHackedGodmode"); - #endif - - // Advanced > World - view_listener_t::addMenu(new LLAdvancedDumpScriptedCamera(), "Advanced.DumpScriptedCamera"); - view_listener_t::addMenu(new LLAdvancedDumpRegionObjectCache(), "Advanced.DumpRegionObjectCache"); - - // Advanced > UI - commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); // sigh! this one opens the MEDIA browser - commit.add("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2)); // this one opens the Web Content floater - view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest"); - view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr"); - view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory"); - commit.add("Advanced.DumpTimers", boost::bind(&handle_dump_timers) ); - commit.add("Advanced.DumpFocusHolder", boost::bind(&handle_dump_focus) ); - view_listener_t::addMenu(new LLAdvancedPrintSelectedObjectInfo(), "Advanced.PrintSelectedObjectInfo"); - view_listener_t::addMenu(new LLAdvancedPrintAgentInfo(), "Advanced.PrintAgentInfo"); - view_listener_t::addMenu(new LLAdvancedPrintTextureMemoryStats(), "Advanced.PrintTextureMemoryStats"); - view_listener_t::addMenu(new LLAdvancedToggleDebugClicks(), "Advanced.ToggleDebugClicks"); - view_listener_t::addMenu(new LLAdvancedCheckDebugClicks(), "Advanced.CheckDebugClicks"); - view_listener_t::addMenu(new LLAdvancedCheckDebugViews(), "Advanced.CheckDebugViews"); - view_listener_t::addMenu(new LLAdvancedToggleDebugViews(), "Advanced.ToggleDebugViews"); - view_listener_t::addMenu(new LLAdvancedToggleXUINameTooltips(), "Advanced.ToggleXUINameTooltips"); - view_listener_t::addMenu(new LLAdvancedCheckXUINameTooltips(), "Advanced.CheckXUINameTooltips"); - view_listener_t::addMenu(new LLAdvancedToggleDebugMouseEvents(), "Advanced.ToggleDebugMouseEvents"); - view_listener_t::addMenu(new LLAdvancedCheckDebugMouseEvents(), "Advanced.CheckDebugMouseEvents"); - view_listener_t::addMenu(new LLAdvancedToggleDebugKeys(), "Advanced.ToggleDebugKeys"); - view_listener_t::addMenu(new LLAdvancedCheckDebugKeys(), "Advanced.CheckDebugKeys"); - view_listener_t::addMenu(new LLAdvancedToggleDebugWindowProc(), "Advanced.ToggleDebugWindowProc"); - view_listener_t::addMenu(new LLAdvancedCheckDebugWindowProc(), "Advanced.CheckDebugWindowProc"); - commit.add("Advanced.ShowSideTray", boost::bind(&handle_show_side_tray)); - - // Advanced > XUI - commit.add("Advanced.ReloadColorSettings", boost::bind(&LLUIColorTable::loadFromSettings, LLUIColorTable::getInstance())); - view_listener_t::addMenu(new LLAdvancedToggleXUINames(), "Advanced.ToggleXUINames"); - view_listener_t::addMenu(new LLAdvancedCheckXUINames(), "Advanced.CheckXUINames"); - view_listener_t::addMenu(new LLAdvancedSendTestIms(), "Advanced.SendTestIMs"); - commit.add("Advanced.FlushNameCaches", boost::bind(&handle_flush_name_caches)); - - // Advanced > Character > Grab Baked Texture - view_listener_t::addMenu(new LLAdvancedGrabBakedTexture(), "Advanced.GrabBakedTexture"); - view_listener_t::addMenu(new LLAdvancedEnableGrabBakedTexture(), "Advanced.EnableGrabBakedTexture"); - - // Advanced > Character > Character Tests - view_listener_t::addMenu(new LLAdvancedAppearanceToXML(), "Advanced.AppearanceToXML"); - view_listener_t::addMenu(new LLAdvancedToggleCharacterGeometry(), "Advanced.ToggleCharacterGeometry"); - - view_listener_t::addMenu(new LLAdvancedTestMale(), "Advanced.TestMale"); - view_listener_t::addMenu(new LLAdvancedTestFemale(), "Advanced.TestFemale"); - view_listener_t::addMenu(new LLAdvancedTogglePG(), "Advanced.TogglePG"); - - // Advanced > Character (toplevel) - view_listener_t::addMenu(new LLAdvancedForceParamsToDefault(), "Advanced.ForceParamsToDefault"); - view_listener_t::addMenu(new LLAdvancedReloadVertexShader(), "Advanced.ReloadVertexShader"); - view_listener_t::addMenu(new LLAdvancedToggleAnimationInfo(), "Advanced.ToggleAnimationInfo"); - view_listener_t::addMenu(new LLAdvancedCheckAnimationInfo(), "Advanced.CheckAnimationInfo"); - view_listener_t::addMenu(new LLAdvancedToggleShowLookAt(), "Advanced.ToggleShowLookAt"); - view_listener_t::addMenu(new LLAdvancedCheckShowLookAt(), "Advanced.CheckShowLookAt"); - view_listener_t::addMenu(new LLAdvancedToggleShowPointAt(), "Advanced.ToggleShowPointAt"); - view_listener_t::addMenu(new LLAdvancedCheckShowPointAt(), "Advanced.CheckShowPointAt"); - view_listener_t::addMenu(new LLAdvancedToggleDebugJointUpdates(), "Advanced.ToggleDebugJointUpdates"); - view_listener_t::addMenu(new LLAdvancedCheckDebugJointUpdates(), "Advanced.CheckDebugJointUpdates"); - view_listener_t::addMenu(new LLAdvancedToggleDisableLOD(), "Advanced.ToggleDisableLOD"); - view_listener_t::addMenu(new LLAdvancedCheckDisableLOD(), "Advanced.CheckDisableLOD"); - view_listener_t::addMenu(new LLAdvancedToggleDebugCharacterVis(), "Advanced.ToggleDebugCharacterVis"); - view_listener_t::addMenu(new LLAdvancedCheckDebugCharacterVis(), "Advanced.CheckDebugCharacterVis"); - view_listener_t::addMenu(new LLAdvancedDumpAttachments(), "Advanced.DumpAttachments"); - view_listener_t::addMenu(new LLAdvancedRebakeTextures(), "Advanced.RebakeTextures"); - view_listener_t::addMenu(new LLAdvancedDebugAvatarTextures(), "Advanced.DebugAvatarTextures"); - view_listener_t::addMenu(new LLAdvancedDumpAvatarLocalTextures(), "Advanced.DumpAvatarLocalTextures"); - // Advanced > Network - view_listener_t::addMenu(new LLAdvancedEnableMessageLog(), "Advanced.EnableMessageLog"); - view_listener_t::addMenu(new LLAdvancedDisableMessageLog(), "Advanced.DisableMessageLog"); - view_listener_t::addMenu(new LLAdvancedDropPacket(), "Advanced.DropPacket"); - - // Advanced > Recorder - view_listener_t::addMenu(new LLAdvancedAgentPilot(), "Advanced.AgentPilot"); - view_listener_t::addMenu(new LLAdvancedToggleAgentPilotLoop(), "Advanced.ToggleAgentPilotLoop"); - view_listener_t::addMenu(new LLAdvancedCheckAgentPilotLoop(), "Advanced.CheckAgentPilotLoop"); - - // Advanced > Debugging - view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint"); - view_listener_t::addMenu(new LLAdvancedForceErrorLlerror(), "Advanced.ForceErrorLlerror"); - view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccess(), "Advanced.ForceErrorBadMemoryAccess"); - view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop"); - view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareException(), "Advanced.ForceErrorSoftwareException"); - view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDriverCrash"); - view_listener_t::addMenu(new LLAdvancedForceErrorDisconnectViewer(), "Advanced.ForceErrorDisconnectViewer"); - - // Advanced (toplevel) - view_listener_t::addMenu(new LLAdvancedToggleShowObjectUpdates(), "Advanced.ToggleShowObjectUpdates"); - view_listener_t::addMenu(new LLAdvancedCheckShowObjectUpdates(), "Advanced.CheckShowObjectUpdates"); - view_listener_t::addMenu(new LLAdvancedCompressImage(), "Advanced.CompressImage"); - view_listener_t::addMenu(new LLAdvancedShowDebugSettings(), "Advanced.ShowDebugSettings"); - view_listener_t::addMenu(new LLAdvancedEnableViewAdminOptions(), "Advanced.EnableViewAdminOptions"); - view_listener_t::addMenu(new LLAdvancedToggleViewAdminOptions(), "Advanced.ToggleViewAdminOptions"); - view_listener_t::addMenu(new LLAdvancedCheckViewAdminOptions(), "Advanced.CheckViewAdminOptions"); - view_listener_t::addMenu(new LLAdvancedRequestAdminStatus(), "Advanced.RequestAdminStatus"); - view_listener_t::addMenu(new LLAdvancedLeaveAdminStatus(), "Advanced.LeaveAdminStatus"); - - - // Admin >Object - view_listener_t::addMenu(new LLAdminForceTakeCopy(), "Admin.ForceTakeCopy"); - view_listener_t::addMenu(new LLAdminHandleObjectOwnerSelf(), "Admin.HandleObjectOwnerSelf"); - view_listener_t::addMenu(new LLAdminHandleObjectOwnerPermissive(), "Admin.HandleObjectOwnerPermissive"); - view_listener_t::addMenu(new LLAdminHandleForceDelete(), "Admin.HandleForceDelete"); - view_listener_t::addMenu(new LLAdminHandleObjectLock(), "Admin.HandleObjectLock"); - view_listener_t::addMenu(new LLAdminHandleObjectAssetIDs(), "Admin.HandleObjectAssetIDs"); - - // Admin >Parcel - view_listener_t::addMenu(new LLAdminHandleForceParcelOwnerToMe(), "Admin.HandleForceParcelOwnerToMe"); - view_listener_t::addMenu(new LLAdminHandleForceParcelToContent(), "Admin.HandleForceParcelToContent"); - view_listener_t::addMenu(new LLAdminHandleClaimPublicLand(), "Admin.HandleClaimPublicLand"); - - // Admin >Region - view_listener_t::addMenu(new LLAdminHandleRegionDumpTempAssetData(), "Admin.HandleRegionDumpTempAssetData"); - // Admin top level - view_listener_t::addMenu(new LLAdminOnSaveState(), "Admin.OnSaveState"); - - // Self context menu - view_listener_t::addMenu(new LLSelfStandUp(), "Self.StandUp"); - enable.add("Self.EnableStandUp", boost::bind(&enable_standup_self)); - view_listener_t::addMenu(new LLSelfSitDown(), "Self.SitDown"); - enable.add("Self.EnableSitDown", boost::bind(&enable_sitdown_self)); - view_listener_t::addMenu(new LLSelfRemoveAllAttachments(), "Self.RemoveAllAttachments"); - - view_listener_t::addMenu(new LLSelfEnableRemoveAllAttachments(), "Self.EnableRemoveAllAttachments"); - - // we don't use boost::bind directly to delay side tray construction - view_listener_t::addMenu( new LLTogglePanelPeopleTab(), "SideTray.PanelPeopleTab"); - - // Avatar pie menu - view_listener_t::addMenu(new LLObjectMute(), "Avatar.Mute"); - view_listener_t::addMenu(new LLAvatarAddFriend(), "Avatar.AddFriend"); - view_listener_t::addMenu(new LLAvatarAddContact(), "Avatar.AddContact"); - commit.add("Avatar.Freeze", boost::bind(&handle_avatar_freeze, LLSD())); - view_listener_t::addMenu(new LLAvatarDebug(), "Avatar.Debug"); - view_listener_t::addMenu(new LLAvatarVisibleDebug(), "Avatar.VisibleDebug"); - view_listener_t::addMenu(new LLAvatarInviteToGroup(), "Avatar.InviteToGroup"); - commit.add("Avatar.Eject", boost::bind(&handle_avatar_eject, LLSD())); - commit.add("Avatar.ShowInspector", boost::bind(&handle_avatar_show_inspector)); - view_listener_t::addMenu(new LLAvatarSendIM(), "Avatar.SendIM"); - view_listener_t::addMenu(new LLAvatarCall(), "Avatar.Call"); - enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall)); - view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse"); - - view_listener_t::addMenu(new LLAvatarEnableAddFriend(), "Avatar.EnableAddFriend"); - enable.add("Avatar.EnableFreezeEject", boost::bind(&enable_freeze_eject, _2)); - - // Object pie menu - view_listener_t::addMenu(new LLObjectBuild(), "Object.Build"); - commit.add("Object.Touch", boost::bind(&handle_object_touch)); - commit.add("Object.SitOrStand", boost::bind(&handle_object_sit_or_stand)); - commit.add("Object.Delete", boost::bind(&handle_object_delete)); - view_listener_t::addMenu(new LLObjectAttachToAvatar(true), "Object.AttachToAvatar"); - view_listener_t::addMenu(new LLObjectAttachToAvatar(false), "Object.AttachAddToAvatar"); - view_listener_t::addMenu(new LLObjectReturn(), "Object.Return"); - view_listener_t::addMenu(new LLObjectReportAbuse(), "Object.ReportAbuse"); - view_listener_t::addMenu(new LLObjectMute(), "Object.Mute"); - - enable.add("Object.VisibleTake", boost::bind(&visible_take_object)); - enable.add("Object.VisibleBuy", boost::bind(&visible_buy_object)); - - commit.add("Object.Buy", boost::bind(&handle_buy)); - commit.add("Object.Edit", boost::bind(&handle_object_edit)); - commit.add("Object.Inspect", boost::bind(&handle_object_inspect)); - commit.add("Object.Open", boost::bind(&handle_object_open)); - commit.add("Object.Take", boost::bind(&handle_take)); - commit.add("Object.ShowInspector", boost::bind(&handle_object_show_inspector)); - enable.add("Object.EnableOpen", boost::bind(&enable_object_open)); - enable.add("Object.EnableTouch", boost::bind(&enable_object_touch, _1)); - enable.add("Object.EnableDelete", boost::bind(&enable_object_delete)); - enable.add("Object.EnableWear", boost::bind(&object_selected_and_point_valid)); - - enable.add("Object.EnableStandUp", boost::bind(&enable_object_stand_up)); - enable.add("Object.EnableSit", boost::bind(&enable_object_sit, _1)); - - view_listener_t::addMenu(new LLObjectEnableReturn(), "Object.EnableReturn"); - view_listener_t::addMenu(new LLObjectEnableReportAbuse(), "Object.EnableReportAbuse"); - - enable.add("Avatar.EnableMute", boost::bind(&enable_object_mute)); - enable.add("Object.EnableMute", boost::bind(&enable_object_mute)); - enable.add("Object.EnableBuy", boost::bind(&enable_buy_object)); - commit.add("Object.ZoomIn", boost::bind(&handle_look_at_selection, "zoom")); - - // Attachment pie menu - enable.add("Attachment.Label", boost::bind(&onEnableAttachmentLabel, _1, _2)); - view_listener_t::addMenu(new LLAttachmentDrop(), "Attachment.Drop"); - view_listener_t::addMenu(new LLAttachmentDetachFromPoint(), "Attachment.DetachFromPoint"); - view_listener_t::addMenu(new LLAttachmentDetach(), "Attachment.Detach"); - view_listener_t::addMenu(new LLAttachmentPointFilled(), "Attachment.PointFilled"); - view_listener_t::addMenu(new LLAttachmentEnableDrop(), "Attachment.EnableDrop"); - view_listener_t::addMenu(new LLAttachmentEnableDetach(), "Attachment.EnableDetach"); - - // Land pie menu - view_listener_t::addMenu(new LLLandBuild(), "Land.Build"); - view_listener_t::addMenu(new LLLandSit(), "Land.Sit"); - view_listener_t::addMenu(new LLLandBuyPass(), "Land.BuyPass"); - view_listener_t::addMenu(new LLLandEdit(), "Land.Edit"); - - view_listener_t::addMenu(new LLLandEnableBuyPass(), "Land.EnableBuyPass"); - commit.add("Land.Buy", boost::bind(&handle_buy_land)); - - // Generic actions - commit.add("ReportAbuse", boost::bind(&handle_report_abuse)); - commit.add("BuyCurrency", boost::bind(&handle_buy_currency)); - view_listener_t::addMenu(new LLShowHelp(), "ShowHelp"); - view_listener_t::addMenu(new LLToggleHelp(), "ToggleHelp"); - view_listener_t::addMenu(new LLPromptShowURL(), "PromptShowURL"); - view_listener_t::addMenu(new LLShowAgentProfile(), "ShowAgentProfile"); - view_listener_t::addMenu(new LLToggleAgentProfile(), "ToggleAgentProfile"); - view_listener_t::addMenu(new LLToggleControl(), "ToggleControl"); - view_listener_t::addMenu(new LLCheckControl(), "CheckControl"); - view_listener_t::addMenu(new LLGoToObject(), "GoToObject"); - commit.add("PayObject", boost::bind(&handle_give_money_dialog)); - - enable.add("EnablePayObject", boost::bind(&enable_pay_object)); - enable.add("EnablePayAvatar", boost::bind(&enable_pay_avatar)); - enable.add("EnableEdit", boost::bind(&enable_object_edit)); - enable.add("VisibleBuild", boost::bind(&enable_object_build)); - - view_listener_t::addMenu(new LLFloaterVisible(), "FloaterVisible"); - view_listener_t::addMenu(new LLShowSidetrayPanel(), "ShowSidetrayPanel"); - view_listener_t::addMenu(new LLSidetrayPanelVisible(), "SidetrayPanelVisible"); - view_listener_t::addMenu(new LLSomethingSelected(), "SomethingSelected"); - view_listener_t::addMenu(new LLSomethingSelectedNoHUD(), "SomethingSelectedNoHUD"); - view_listener_t::addMenu(new LLEditableSelected(), "EditableSelected"); - view_listener_t::addMenu(new LLEditableSelectedMono(), "EditableSelectedMono"); - - view_listener_t::addMenu(new LLToggleUIHints(), "ToggleUIHints"); - - commit.add("Destination.show", boost::bind(&toggle_destination_and_avatar_picker, 0)); - commit.add("Avatar.show", boost::bind(&toggle_destination_and_avatar_picker, 1)); -} +/**
+ * @file llviewermenu.cpp
+ * @brief Builds menus out of items.
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llviewermenu.h"
+
+// linden library includes
+#include "llavatarnamecache.h" // IDEVO
+#include "llfloaterreg.h"
+#include "llcombobox.h"
+#include "llinventorypanel.h"
+#include "llnotifications.h"
+#include "llnotificationsutil.h"
+
+// newview includes
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llagentwearables.h"
+#include "llagentpilot.h"
+#include "llbottomtray.h"
+#include "llcompilequeue.h"
+#include "llconsole.h"
+#include "lldebugview.h"
+#include "llfilepicker.h"
+#include "llfirstuse.h"
+#include "llfloaterbuy.h"
+#include "llfloaterbuycontents.h"
+#include "llbuycurrencyhtml.h"
+#include "llfloatergodtools.h"
+#include "llfloaterinventory.h"
+#include "llfloaterland.h"
+#include "llfloaterpay.h"
+#include "llfloaterreporter.h"
+#include "llfloatersearch.h"
+#include "llfloaterscriptdebug.h"
+#include "llfloatersnapshot.h"
+#include "llfloatertools.h"
+#include "llfloaterworldmap.h"
+#include "llavataractions.h"
+#include "lllandmarkactions.h"
+#include "llgroupmgr.h"
+#include "lltooltip.h"
+#include "llhints.h"
+#include "llhudeffecttrail.h"
+#include "llhudmanager.h"
+#include "llimview.h"
+#include "llinventorybridge.h"
+#include "llinventorydefines.h"
+#include "llinventoryfunctions.h"
+#include "llpanellogin.h"
+#include "llpanelblockedlist.h"
+#include "llmenucommands.h"
+#include "llmoveview.h"
+#include "llparcel.h"
+#include "llrootview.h"
+#include "llselectmgr.h"
+#include "llsidetray.h"
+#include "llstatusbar.h"
+#include "lltextureview.h"
+#include "lltoolcomp.h"
+#include "lltoolmgr.h"
+#include "lltoolpie.h"
+#include "lltoolselectland.h"
+#include "lltrans.h"
+#include "llviewergenericmessage.h"
+#include "llviewerhelp.h"
+#include "llviewermenufile.h" // init_menu_file()
+#include "llviewermessage.h"
+#include "llviewernetwork.h"
+#include "llviewerobjectlist.h"
+#include "llviewerparcelmgr.h"
+#include "llviewerstats.h"
+#include "llvoavatarself.h"
+#include "llworldmap.h"
+#include "pipeline.h"
+#include "llviewerjoystick.h"
+#include "llwlanimator.h"
+#include "llwlparammanager.h"
+#include "llfloatercamera.h"
+#include "lluilistener.h"
+#include "llappearancemgr.h"
+#include "lltrans.h"
+#include "lleconomy.h"
+#include "boost/unordered_map.hpp"
+
+using namespace LLVOAvatarDefines;
+
+static boost::unordered_map<std::string, LLStringExplicit> sDefaultItemLabels;
+
+BOOL enable_land_build(void*);
+BOOL enable_object_build(void*);
+
+LLVOAvatar* find_avatar_from_object( LLViewerObject* object );
+LLVOAvatar* find_avatar_from_object( const LLUUID& object_id );
+
+void handle_test_load_url(void*);
+
+//
+// Evil hackish imported globals
+
+//extern BOOL gHideSelectedObjects;
+//extern BOOL gAllowSelectAvatar;
+//extern BOOL gDebugAvatarRotation;
+extern BOOL gDebugClicks;
+extern BOOL gDebugWindowProc;
+//extern BOOL gDebugTextEditorTips;
+//extern BOOL gDebugSelectMgr;
+
+//
+// Globals
+//
+
+LLMenuBarGL *gMenuBarView = NULL;
+LLViewerMenuHolderGL *gMenuHolder = NULL;
+LLMenuGL *gPopupMenuView = NULL;
+LLMenuGL *gEditMenu = NULL;
+LLMenuBarGL *gLoginMenuBarView = NULL;
+
+// Pie menus
+LLContextMenu *gMenuAvatarSelf = NULL;
+LLContextMenu *gMenuAvatarOther = NULL;
+LLContextMenu *gMenuObject = NULL;
+LLContextMenu *gMenuAttachmentSelf = NULL;
+LLContextMenu *gMenuAttachmentOther = NULL;
+LLContextMenu *gMenuLand = NULL;
+
+const std::string SAVE_INTO_INVENTORY("Save Object Back to My Inventory");
+const std::string SAVE_INTO_TASK_INVENTORY("Save Object Back to Object Contents");
+
+LLMenuGL* gAttachSubMenu = NULL;
+LLMenuGL* gDetachSubMenu = NULL;
+LLMenuGL* gTakeOffClothes = NULL;
+LLContextMenu* gAttachScreenPieMenu = NULL;
+LLContextMenu* gAttachPieMenu = NULL;
+LLContextMenu* gAttachBodyPartPieMenus[8];
+LLContextMenu* gDetachPieMenu = NULL;
+LLContextMenu* gDetachScreenPieMenu = NULL;
+LLContextMenu* gDetachBodyPartPieMenus[8];
+
+LLMenuItemCallGL* gAFKMenu = NULL;
+LLMenuItemCallGL* gBusyMenu = NULL;
+
+//
+// Local prototypes
+
+// File Menu
+const char* upload_pick(void* data);
+void handle_compress_image(void*);
+
+
+// Edit menu
+void handle_dump_group_info(void *);
+void handle_dump_capabilities_info(void *);
+
+// Advanced->Consoles menu
+void handle_region_dump_settings(void*);
+void handle_region_dump_temp_asset_data(void*);
+void handle_region_clear_temp_asset_data(void*);
+
+// Object pie menu
+BOOL sitting_on_selection();
+
+void near_sit_object();
+//void label_sit_or_stand(std::string& label, void*);
+// buy and take alias into the same UI positions, so these
+// declarations handle this mess.
+BOOL is_selection_buy_not_take();
+S32 selection_price();
+BOOL enable_take();
+void handle_take();
+void handle_object_show_inspector();
+void handle_avatar_show_inspector();
+bool confirm_take(const LLSD& notification, const LLSD& response);
+
+void handle_buy_object(LLSaleInfo sale_info);
+void handle_buy_contents(LLSaleInfo sale_info);
+
+// Land pie menu
+void near_sit_down_point(BOOL success, void *);
+
+// Avatar pie menu
+
+// Debug menu
+
+
+void velocity_interpolate( void* );
+
+void handle_rebake_textures(void*);
+BOOL check_admin_override(void*);
+void handle_admin_override_toggle(void*);
+#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
+void handle_toggle_hacked_godmode(void*);
+BOOL check_toggle_hacked_godmode(void*);
+bool enable_toggle_hacked_godmode(void*);
+#endif
+
+void toggle_show_xui_names(void *);
+BOOL check_show_xui_names(void *);
+
+// Debug UI
+
+void handle_buy_currency_test(void*);
+
+void handle_god_mode(void*);
+
+// God menu
+void handle_leave_god_mode(void*);
+
+
+void handle_reset_view();
+
+void handle_duplicate_in_place(void*);
+
+
+void handle_object_owner_self(void*);
+void handle_object_owner_permissive(void*);
+void handle_object_lock(void*);
+void handle_object_asset_ids(void*);
+void force_take_copy(void*);
+#ifdef _CORY_TESTING
+void force_export_copy(void*);
+void force_import_geometry(void*);
+#endif
+
+void handle_force_parcel_owner_to_me(void*);
+void handle_force_parcel_to_content(void*);
+void handle_claim_public_land(void*);
+
+void handle_god_request_avatar_geometry(void *); // Hack for easy testing of new avatar geometry
+void reload_vertex_shader(void *);
+void handle_disconnect_viewer(void *);
+
+void force_error_breakpoint(void *);
+void force_error_llerror(void *);
+void force_error_bad_memory_access(void *);
+void force_error_infinite_loop(void *);
+void force_error_software_exception(void *);
+void force_error_driver_crash(void *);
+
+void handle_force_delete(void*);
+void print_object_info(void*);
+void print_agent_nvpairs(void*);
+void toggle_debug_menus(void*);
+void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExtStat ext_status);
+void dump_select_mgr(void*);
+
+void dump_inventory(void*);
+void toggle_visibility(void*);
+BOOL get_visibility(void*);
+
+// Avatar Pie menu
+void request_friendship(const LLUUID& agent_id);
+
+// Tools menu
+void handle_selected_texture_info(void*);
+
+void handle_dump_followcam(void*);
+void handle_viewer_enable_message_log(void*);
+void handle_viewer_disable_message_log(void*);
+
+BOOL enable_buy_land(void*);
+
+// Help menu
+
+void handle_test_male(void *);
+void handle_test_female(void *);
+void handle_toggle_pg(void*);
+void handle_dump_attachments(void *);
+void handle_dump_avatar_local_textures(void*);
+void handle_debug_avatar_textures(void*);
+void handle_grab_baked_texture(void*);
+BOOL enable_grab_baked_texture(void*);
+void handle_dump_region_object_cache(void*);
+
+BOOL enable_save_into_inventory(void*);
+BOOL enable_save_into_task_inventory(void*);
+
+BOOL enable_detach(const LLSD& = LLSD());
+void menu_toggle_attached_lights(void* user_data);
+void menu_toggle_attached_particles(void* user_data);
+
+class LLMenuParcelObserver : public LLParcelObserver
+{
+public:
+ LLMenuParcelObserver();
+ ~LLMenuParcelObserver();
+ virtual void changed();
+};
+
+static LLMenuParcelObserver* gMenuParcelObserver = NULL;
+
+static LLUIListener sUIListener;
+
+LLMenuParcelObserver::LLMenuParcelObserver()
+{
+ LLViewerParcelMgr::getInstance()->addObserver(this);
+}
+
+LLMenuParcelObserver::~LLMenuParcelObserver()
+{
+ LLViewerParcelMgr::getInstance()->removeObserver(this);
+}
+
+void LLMenuParcelObserver::changed()
+{
+ gMenuHolder->childSetEnabled("Land Buy Pass", LLPanelLandGeneral::enableBuyPass(NULL));
+
+ BOOL buyable = enable_buy_land(NULL);
+ gMenuHolder->childSetEnabled("Land Buy", buyable);
+ gMenuHolder->childSetEnabled("Buy Land...", buyable);
+}
+
+
+void initialize_menus();
+
+//-----------------------------------------------------------------------------
+// Initialize main menus
+//
+// HOW TO NAME MENUS:
+//
+// First Letter Of Each Word Is Capitalized, Even At Or And
+//
+// Items that lead to dialog boxes end in "..."
+//
+// Break up groups of more than 6 items with separators
+//-----------------------------------------------------------------------------
+
+void set_underclothes_menu_options()
+{
+ if (gMenuHolder && gAgent.isTeen())
+ {
+ gMenuHolder->getChild<LLView>("Self Underpants")->setVisible(FALSE);
+ gMenuHolder->getChild<LLView>("Self Undershirt")->setVisible(FALSE);
+ }
+ if (gMenuBarView && gAgent.isTeen())
+ {
+ gMenuBarView->getChild<LLView>("Menu Underpants")->setVisible(FALSE);
+ gMenuBarView->getChild<LLView>("Menu Undershirt")->setVisible(FALSE);
+ }
+}
+
+void init_menus()
+{
+ S32 top = gViewerWindow->getRootView()->getRect().getHeight();
+
+ // Initialize actions
+ initialize_menus();
+
+ ///
+ /// Popup menu
+ ///
+ /// The popup menu is now populated by the show_context_menu()
+ /// method.
+
+ LLMenuGL::Params menu_params;
+ menu_params.name = "Popup";
+ menu_params.visible = false;
+ gPopupMenuView = LLUICtrlFactory::create<LLMenuGL>(menu_params);
+ gMenuHolder->addChild( gPopupMenuView );
+
+ ///
+ /// Context menus
+ ///
+
+ const widget_registry_t& registry =
+ LLViewerMenuHolderGL::child_registry_t::instance();
+ gEditMenu = LLUICtrlFactory::createFromFile<LLMenuGL>("menu_edit.xml", gMenuHolder, registry);
+ gMenuAvatarSelf = LLUICtrlFactory::createFromFile<LLContextMenu>(
+ "menu_avatar_self.xml", gMenuHolder, registry);
+ gMenuAvatarOther = LLUICtrlFactory::createFromFile<LLContextMenu>(
+ "menu_avatar_other.xml", gMenuHolder, registry);
+
+ gDetachScreenPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Detach HUD", true);
+ gDetachPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Detach", true);
+
+ gMenuObject = LLUICtrlFactory::createFromFile<LLContextMenu>(
+ "menu_object.xml", gMenuHolder, registry);
+
+ gAttachScreenPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Attach HUD");
+ gAttachPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Attach");
+
+ gMenuAttachmentSelf = LLUICtrlFactory::createFromFile<LLContextMenu>(
+ "menu_attachment_self.xml", gMenuHolder, registry);
+ gMenuAttachmentOther = LLUICtrlFactory::createFromFile<LLContextMenu>(
+ "menu_attachment_other.xml", gMenuHolder, registry);
+
+ gMenuLand = LLUICtrlFactory::createFromFile<LLContextMenu>(
+ "menu_land.xml", gMenuHolder, registry);
+
+ ///
+ /// set up the colors
+ ///
+ LLColor4 color;
+
+ LLColor4 context_menu_color = LLUIColorTable::instance().getColor("MenuPopupBgColor");
+
+ gMenuAvatarSelf->setBackgroundColor( context_menu_color );
+ gMenuAvatarOther->setBackgroundColor( context_menu_color );
+ gMenuObject->setBackgroundColor( context_menu_color );
+ gMenuAttachmentSelf->setBackgroundColor( context_menu_color );
+ gMenuAttachmentOther->setBackgroundColor( context_menu_color );
+
+ gMenuLand->setBackgroundColor( context_menu_color );
+
+ color = LLUIColorTable::instance().getColor( "MenuPopupBgColor" );
+ gPopupMenuView->setBackgroundColor( color );
+
+ // If we are not in production, use a different color to make it apparent.
+ if (LLGridManager::getInstance()->isInProductionGrid())
+ {
+ color = LLUIColorTable::instance().getColor( "MenuBarBgColor" );
+ }
+ else
+ {
+ color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" );
+ }
+ gMenuBarView = LLUICtrlFactory::getInstance()->createFromFile<LLMenuBarGL>("menu_viewer.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ gMenuBarView->setRect(LLRect(0, top, 0, top - MENU_BAR_HEIGHT));
+ gMenuBarView->setBackgroundColor( color );
+
+ LLView* menu_bar_holder = gViewerWindow->getRootView()->getChildView("menu_bar_holder");
+ menu_bar_holder->addChild(gMenuBarView);
+
+ gViewerWindow->setMenuBackgroundColor(false,
+ LLGridManager::getInstance()->isInProductionGrid());
+
+ // Assume L$10 for now, the server will tell us the real cost at login
+ // *TODO:Also fix cost in llfolderview.cpp for Inventory menus
+ const std::string upload_cost("10");
+ gMenuHolder->childSetLabelArg("Upload Image", "[COST]", upload_cost);
+ gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", upload_cost);
+ gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", upload_cost);
+ gMenuHolder->childSetLabelArg("Bulk Upload", "[COST]", upload_cost);
+
+ gAFKMenu = gMenuBarView->getChild<LLMenuItemCallGL>("Set Away", TRUE);
+ gBusyMenu = gMenuBarView->getChild<LLMenuItemCallGL>("Set Busy", TRUE);
+ gAttachSubMenu = gMenuBarView->findChildMenuByName("Attach Object", TRUE);
+ gDetachSubMenu = gMenuBarView->findChildMenuByName("Detach Object", TRUE);
+
+#if !MEM_TRACK_MEM
+ // Don't display the Memory console menu if the feature is turned off
+ LLMenuItemCheckGL *memoryMenu = gMenuBarView->getChild<LLMenuItemCheckGL>("Memory", TRUE);
+ if (memoryMenu)
+ {
+ memoryMenu->setVisible(FALSE);
+ }
+#endif
+
+ gMenuBarView->createJumpKeys();
+
+ // Let land based option enable when parcel changes
+ gMenuParcelObserver = new LLMenuParcelObserver();
+
+ gLoginMenuBarView = LLUICtrlFactory::getInstance()->createFromFile<LLMenuBarGL>("menu_login.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ gLoginMenuBarView->arrangeAndClear();
+ LLRect menuBarRect = gLoginMenuBarView->getRect();
+ menuBarRect.setLeftTopAndSize(0, menu_bar_holder->getRect().getHeight(), menuBarRect.getWidth(), menuBarRect.getHeight());
+ gLoginMenuBarView->setRect(menuBarRect);
+ gLoginMenuBarView->setBackgroundColor( color );
+ menu_bar_holder->addChild(gLoginMenuBarView);
+
+ // tooltips are on top of EVERYTHING, including menus
+ gViewerWindow->getRootView()->sendChildToFront(gToolTipView);
+}
+
+///////////////////
+// SHOW CONSOLES //
+///////////////////
+
+
+class LLAdvancedToggleConsole : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string console_type = userdata.asString();
+ if ("texture" == console_type)
+ {
+ toggle_visibility( (void*)gTextureView );
+ }
+ else if ("debug" == console_type)
+ {
+ toggle_visibility( (void*)static_cast<LLUICtrl*>(gDebugView->mDebugConsolep));
+ }
+ else if (gTextureSizeView && "texture size" == console_type)
+ {
+ toggle_visibility( (void*)gTextureSizeView );
+ }
+ else if (gTextureCategoryView && "texture category" == console_type)
+ {
+ toggle_visibility( (void*)gTextureCategoryView );
+ }
+ else if ("fast timers" == console_type)
+ {
+ toggle_visibility( (void*)gDebugView->mFastTimerView );
+ }
+#if MEM_TRACK_MEM
+ else if ("memory view" == console_type)
+ {
+ toggle_visibility( (void*)gDebugView->mMemoryView );
+ }
+#endif
+ return true;
+ }
+};
+class LLAdvancedCheckConsole : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string console_type = userdata.asString();
+ bool new_value = false;
+ if ("texture" == console_type)
+ {
+ new_value = get_visibility( (void*)gTextureView );
+ }
+ else if ("debug" == console_type)
+ {
+ new_value = get_visibility( (void*)((LLView*)gDebugView->mDebugConsolep) );
+ }
+ else if (gTextureSizeView && "texture size" == console_type)
+ {
+ new_value = get_visibility( (void*)gTextureSizeView );
+ }
+ else if (gTextureCategoryView && "texture category" == console_type)
+ {
+ new_value = get_visibility( (void*)gTextureCategoryView );
+ }
+ else if ("fast timers" == console_type)
+ {
+ new_value = get_visibility( (void*)gDebugView->mFastTimerView );
+ }
+#if MEM_TRACK_MEM
+ else if ("memory view" == console_type)
+ {
+ new_value = get_visibility( (void*)gDebugView->mMemoryView );
+ }
+#endif
+
+ return new_value;
+ }
+};
+
+
+//////////////////////////
+// DUMP INFO TO CONSOLE //
+//////////////////////////
+
+
+class LLAdvancedDumpInfoToConsole : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string info_type = userdata.asString();
+ if ("region" == info_type)
+ {
+ handle_region_dump_settings(NULL);
+ }
+ else if ("group" == info_type)
+ {
+ handle_dump_group_info(NULL);
+ }
+ else if ("capabilities" == info_type)
+ {
+ handle_dump_capabilities_info(NULL);
+ }
+ return true;
+ }
+};
+
+
+//////////////
+// HUD INFO //
+//////////////
+
+
+class LLAdvancedToggleHUDInfo : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string info_type = userdata.asString();
+
+ if ("camera" == info_type)
+ {
+ gDisplayCameraPos = !(gDisplayCameraPos);
+ }
+ else if ("wind" == info_type)
+ {
+ gDisplayWindInfo = !(gDisplayWindInfo);
+ }
+ else if ("fov" == info_type)
+ {
+ gDisplayFOV = !(gDisplayFOV);
+ }
+ else if ("badge" == info_type)
+ {
+ gDisplayBadge = !(gDisplayBadge);
+ }
+ return true;
+ }
+};
+
+class LLAdvancedCheckHUDInfo : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string info_type = userdata.asString();
+ bool new_value = false;
+ if ("camera" == info_type)
+ {
+ new_value = gDisplayCameraPos;
+ }
+ else if ("wind" == info_type)
+ {
+ new_value = gDisplayWindInfo;
+ }
+ else if ("fov" == info_type)
+ {
+ new_value = gDisplayFOV;
+ }
+ else if ("badge" == info_type)
+ {
+ new_value = gDisplayBadge;
+ }
+ return new_value;
+ }
+};
+
+
+//////////////
+// FLYING //
+//////////////
+
+class LLAdvancedAgentFlyingInfo : public view_listener_t
+{
+ bool handleEvent(const LLSD&)
+ {
+ return gAgent.getFlying();
+ }
+};
+
+
+///////////////////////
+// CLEAR GROUP CACHE //
+///////////////////////
+
+class LLAdvancedClearGroupCache : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLGroupMgr::debugClearAllGroups(NULL);
+ return true;
+ }
+};
+
+
+
+
+/////////////////
+// RENDER TYPE //
+/////////////////
+U32 render_type_from_string(std::string render_type)
+{
+ if ("simple" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_SIMPLE;
+ }
+ else if ("alpha" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_ALPHA;
+ }
+ else if ("tree" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_TREE;
+ }
+ else if ("character" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_AVATAR;
+ }
+ else if ("surfacePath" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_TERRAIN;
+ }
+ else if ("sky" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_SKY;
+ }
+ else if ("water" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_WATER;
+ }
+ else if ("ground" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_GROUND;
+ }
+ else if ("volume" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_VOLUME;
+ }
+ else if ("grass" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_GRASS;
+ }
+ else if ("clouds" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_CLOUDS;
+ }
+ else if ("particles" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_PARTICLES;
+ }
+ else if ("bump" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_BUMP;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+class LLAdvancedToggleRenderType : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ U32 render_type = render_type_from_string( userdata.asString() );
+ if ( render_type != 0 )
+ {
+ LLPipeline::toggleRenderTypeControl( (void*)render_type );
+ }
+ return true;
+ }
+};
+
+
+class LLAdvancedCheckRenderType : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ U32 render_type = render_type_from_string( userdata.asString() );
+ bool new_value = false;
+
+ if ( render_type != 0 )
+ {
+ new_value = LLPipeline::hasRenderTypeControl( (void*)render_type );
+ }
+
+ return new_value;
+ }
+};
+
+
+/////////////
+// FEATURE //
+/////////////
+U32 feature_from_string(std::string feature)
+{
+ if ("ui" == feature)
+ {
+ return LLPipeline::RENDER_DEBUG_FEATURE_UI;
+ }
+ else if ("selected" == feature)
+ {
+ return LLPipeline::RENDER_DEBUG_FEATURE_SELECTED;
+ }
+ else if ("highlighted" == feature)
+ {
+ return LLPipeline::RENDER_DEBUG_FEATURE_HIGHLIGHTED;
+ }
+ else if ("dynamic textures" == feature)
+ {
+ return LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES;
+ }
+ else if ("foot shadows" == feature)
+ {
+ return LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS;
+ }
+ else if ("fog" == feature)
+ {
+ return LLPipeline::RENDER_DEBUG_FEATURE_FOG;
+ }
+ else if ("fr info" == feature)
+ {
+ return LLPipeline::RENDER_DEBUG_FEATURE_FR_INFO;
+ }
+ else if ("flexible" == feature)
+ {
+ return LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE;
+ }
+ else
+ {
+ return 0;
+ }
+};
+
+
+class LLAdvancedToggleFeature : public view_listener_t{
+ bool handleEvent(const LLSD& userdata)
+ {
+ U32 feature = feature_from_string( userdata.asString() );
+ if ( feature != 0 )
+ {
+ LLPipeline::toggleRenderDebugFeature( (void*)feature );
+ }
+ return true;
+ }
+};
+
+class LLAdvancedCheckFeature : public view_listener_t
+{bool handleEvent(const LLSD& userdata)
+{
+ U32 feature = feature_from_string( userdata.asString() );
+ bool new_value = false;
+
+ if ( feature != 0 )
+ {
+ new_value = LLPipeline::toggleRenderDebugFeatureControl( (void*)feature );
+ }
+
+ return new_value;
+}
+};
+
+void toggle_destination_and_avatar_picker(const LLSD& show)
+{
+ S32 panel_idx = show.isDefined() ? show.asInteger() : -1;
+ LLView* container = gViewerWindow->getRootView()->getChildView("avatar_picker_and_destination_guide_container");
+ LLMediaCtrl* destinations = container->findChild<LLMediaCtrl>("destination_guide_contents");
+ LLMediaCtrl* avatar_picker = container->findChild<LLMediaCtrl>("avatar_picker_contents");
+ LLButton* avatar_btn = gViewerWindow->getRootView()->getChildView("bottom_tray")->getChild<LLButton>("avatar_btn");
+ LLButton* destination_btn = gViewerWindow->getRootView()->getChildView("bottom_tray")->getChild<LLButton>("destination_btn");
+
+ switch(panel_idx)
+ {
+ case 0:
+ if (!destinations->getVisible())
+ {
+ container->setVisible(true);
+ destinations->setVisible(true);
+ avatar_picker->setVisible(false);
+ LLFirstUse::notUsingDestinationGuide(false);
+ avatar_btn->setToggleState(false);
+ destination_btn->setToggleState(true);
+ return;
+ }
+ break;
+ case 1:
+ if (!avatar_picker->getVisible())
+ {
+ container->setVisible(true);
+ destinations->setVisible(false);
+ avatar_picker->setVisible(true);
+ avatar_btn->setToggleState(true);
+ destination_btn->setToggleState(false);
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+
+ container->setVisible(false);
+ destinations->setVisible(false);
+ avatar_picker->setVisible(false);
+ avatar_btn->setToggleState(false);
+ destination_btn->setToggleState(false);
+};
+
+
+//////////////////
+// INFO DISPLAY //
+//////////////////
+U32 info_display_from_string(std::string info_display)
+{
+ if ("verify" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_VERIFY;
+ }
+ else if ("bboxes" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_BBOXES;
+ }
+ else if ("points" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_POINTS;
+ }
+ else if ("octree" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_OCTREE;
+ }
+ else if ("shadow frusta" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA;
+ }
+ else if ("occlusion" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_OCCLUSION;
+ }
+ else if ("render batches" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_BATCH_SIZE;
+ }
+ else if ("update type" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_UPDATE_TYPE;
+ }
+ else if ("texture anim" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_TEXTURE_ANIM;
+ }
+ else if ("texture priority" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY;
+ }
+ else if ("shame" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_SHAME;
+ }
+ else if ("texture area" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_TEXTURE_AREA;
+ }
+ else if ("face area" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_FACE_AREA;
+ }
+ else if ("lights" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_LIGHTS;
+ }
+ else if ("particles" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_PARTICLES;
+ }
+ else if ("composition" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_COMPOSITION;
+ }
+ else if ("glow" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_GLOW;
+ }
+ else if ("collision skeleton" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_AVATAR_VOLUME;
+ }
+ else if ("raycast" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_RAYCAST;
+ }
+ else if ("agent target" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_AGENT_TARGET;
+ }
+ else
+ {
+ return 0;
+ }
+};
+
+class LLAdvancedToggleInfoDisplay : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ U32 info_display = info_display_from_string( userdata.asString() );
+
+ if ( info_display != 0 )
+ {
+ LLPipeline::toggleRenderDebug( (void*)info_display );
+ }
+
+ return true;
+ }
+};
+
+
+class LLAdvancedCheckInfoDisplay : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ U32 info_display = info_display_from_string( userdata.asString() );
+ bool new_value = false;
+
+ if ( info_display != 0 )
+ {
+ new_value = LLPipeline::toggleRenderDebugControl( (void*)info_display );
+ }
+
+ return new_value;
+ }
+};
+
+
+///////////////////////////
+//// RANDOMIZE FRAMERATE //
+///////////////////////////
+
+
+class LLAdvancedToggleRandomizeFramerate : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gRandomizeFramerate = !(gRandomizeFramerate);
+ return true;
+ }
+};
+
+class LLAdvancedCheckRandomizeFramerate : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gRandomizeFramerate;
+ return new_value;
+ }
+};
+
+void run_vectorize_perf_test(void *)
+{
+ gSavedSettings.setBOOL("VectorizePerfTest", TRUE);
+}
+
+
+////////////////////////////////
+// RUN Vectorized Perform Test//
+////////////////////////////////
+
+
+class LLAdvancedVectorizePerfTest : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ run_vectorize_perf_test(NULL);
+ return true;
+ }
+};
+
+///////////////////////////
+//// PERIODIC SLOW FRAME //
+///////////////////////////
+
+
+class LLAdvancedTogglePeriodicSlowFrame : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gPeriodicSlowFrame = !(gPeriodicSlowFrame);
+ return true;
+ }
+};
+
+class LLAdvancedCheckPeriodicSlowFrame : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gPeriodicSlowFrame;
+ return new_value;
+ }
+};
+
+
+
+////////////////
+// FRAME TEST //
+////////////////
+
+
+class LLAdvancedToggleFrameTest : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLPipeline::sRenderFrameTest = !(LLPipeline::sRenderFrameTest);
+ return true;
+ }
+};
+
+class LLAdvancedCheckFrameTest : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLPipeline::sRenderFrameTest;
+ return new_value;
+ }
+};
+
+
+///////////////////////////
+// SELECTED TEXTURE INFO //
+///////////////////////////
+
+
+class LLAdvancedSelectedTextureInfo : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_selected_texture_info(NULL);
+ return true;
+ }
+};
+
+//////////////////////
+// TOGGLE WIREFRAME //
+//////////////////////
+
+class LLAdvancedToggleWireframe : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gUseWireframe = !(gUseWireframe);
+ LLPipeline::updateRenderDeferred();
+ gPipeline.resetVertexBuffers();
+ return true;
+ }
+};
+
+class LLAdvancedCheckWireframe : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gUseWireframe;
+ return new_value;
+ }
+};
+
+//////////////////////
+// TEXTURE ATLAS //
+//////////////////////
+
+class LLAdvancedToggleTextureAtlas : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLViewerTexture::sUseTextureAtlas = !LLViewerTexture::sUseTextureAtlas;
+ gSavedSettings.setBOOL("EnableTextureAtlas", LLViewerTexture::sUseTextureAtlas) ;
+ return true;
+ }
+};
+
+class LLAdvancedCheckTextureAtlas : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLViewerTexture::sUseTextureAtlas; // <-- make this using LLCacheControl
+ return new_value;
+ }
+};
+
+//////////////////////////
+// DUMP SCRIPTED CAMERA //
+//////////////////////////
+
+class LLAdvancedDumpScriptedCamera : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_dump_followcam(NULL);
+ return true;
+}
+};
+
+
+
+//////////////////////////////
+// DUMP REGION OBJECT CACHE //
+//////////////////////////////
+
+
+class LLAdvancedDumpRegionObjectCache : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+{
+ handle_dump_region_object_cache(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedBuyCurrencyTest : public view_listener_t
+ {
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_buy_currency_test(NULL);
+ return true;
+ }
+};
+
+
+/////////////////////
+// DUMP SELECT MGR //
+/////////////////////
+
+
+class LLAdvancedDumpSelectMgr : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ dump_select_mgr(NULL);
+ return true;
+ }
+};
+
+
+
+////////////////////
+// DUMP INVENTORY //
+////////////////////
+
+
+class LLAdvancedDumpInventory : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ dump_inventory(NULL);
+ return true;
+ }
+};
+
+
+
+////////////////////////////////
+// PRINT SELECTED OBJECT INFO //
+////////////////////////////////
+
+
+class LLAdvancedPrintSelectedObjectInfo : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ print_object_info(NULL);
+ return true;
+ }
+};
+
+
+
+//////////////////////
+// PRINT AGENT INFO //
+//////////////////////
+
+
+class LLAdvancedPrintAgentInfo : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ print_agent_nvpairs(NULL);
+ return true;
+ }
+};
+
+
+
+////////////////////////////////
+// PRINT TEXTURE MEMORY STATS //
+////////////////////////////////
+
+
+class LLAdvancedPrintTextureMemoryStats : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ output_statistics(NULL);
+ return true;
+ }
+};
+
+//////////////////
+// DEBUG CLICKS //
+//////////////////
+
+
+class LLAdvancedToggleDebugClicks : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gDebugClicks = !(gDebugClicks);
+ return true;
+ }
+};
+
+class LLAdvancedCheckDebugClicks : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gDebugClicks;
+ return new_value;
+ }
+};
+
+
+
+/////////////////
+// DEBUG VIEWS //
+/////////////////
+
+
+class LLAdvancedToggleDebugViews : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLView::sDebugRects = !(LLView::sDebugRects);
+ return true;
+ }
+};
+
+class LLAdvancedCheckDebugViews : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLView::sDebugRects;
+ return new_value;
+ }
+};
+
+
+
+///////////////////////
+// XUI NAME TOOLTIPS //
+///////////////////////
+
+
+class LLAdvancedToggleXUINameTooltips : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ toggle_show_xui_names(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedCheckXUINameTooltips : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = check_show_xui_names(NULL);
+ return new_value;
+ }
+};
+
+
+
+////////////////////////
+// DEBUG MOUSE EVENTS //
+////////////////////////
+
+
+class LLAdvancedToggleDebugMouseEvents : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLView::sDebugMouseHandling = !(LLView::sDebugMouseHandling);
+ return true;
+ }
+};
+
+class LLAdvancedCheckDebugMouseEvents : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLView::sDebugMouseHandling;
+ return new_value;
+ }
+};
+
+
+
+////////////////
+// DEBUG KEYS //
+////////////////
+
+
+class LLAdvancedToggleDebugKeys : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLView::sDebugKeys = !(LLView::sDebugKeys);
+ return true;
+ }
+};
+
+class LLAdvancedCheckDebugKeys : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLView::sDebugKeys;
+ return new_value;
+ }
+};
+
+
+
+///////////////////////
+// DEBUG WINDOW PROC //
+///////////////////////
+
+
+class LLAdvancedToggleDebugWindowProc : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gDebugWindowProc = !(gDebugWindowProc);
+ return true;
+ }
+};
+
+class LLAdvancedCheckDebugWindowProc : public view_listener_t
+ {
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gDebugWindowProc;
+ return new_value;
+ }
+};
+
+// ------------------------------XUI MENU ---------------------------
+
+class LLAdvancedSendTestIms : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLIMModel::instance().testMessages();
+ return true;
+}
+};
+
+
+///////////////
+// XUI NAMES //
+///////////////
+
+
+class LLAdvancedToggleXUINames : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ toggle_show_xui_names(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedCheckXUINames : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = check_show_xui_names(NULL);
+ return new_value;
+ }
+};
+
+
+////////////////////////
+// GRAB BAKED TEXTURE //
+////////////////////////
+
+
+class LLAdvancedGrabBakedTexture : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string texture_type = userdata.asString();
+ if ("iris" == texture_type)
+ {
+ handle_grab_baked_texture( (void*)BAKED_EYES );
+ }
+ else if ("head" == texture_type)
+ {
+ handle_grab_baked_texture( (void*)BAKED_HEAD );
+ }
+ else if ("upper" == texture_type)
+ {
+ handle_grab_baked_texture( (void*)BAKED_UPPER );
+ }
+ else if ("lower" == texture_type)
+ {
+ handle_grab_baked_texture( (void*)BAKED_LOWER );
+ }
+ else if ("skirt" == texture_type)
+ {
+ handle_grab_baked_texture( (void*)BAKED_SKIRT );
+ }
+ else if ("hair" == texture_type)
+ {
+ handle_grab_baked_texture( (void*)BAKED_HAIR );
+ }
+
+ return true;
+ }
+};
+
+class LLAdvancedEnableGrabBakedTexture : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+{
+ std::string texture_type = userdata.asString();
+ bool new_value = false;
+
+ if ("iris" == texture_type)
+ {
+ new_value = enable_grab_baked_texture( (void*)BAKED_EYES );
+ }
+ else if ("head" == texture_type)
+ {
+ new_value = enable_grab_baked_texture( (void*)BAKED_HEAD );
+ }
+ else if ("upper" == texture_type)
+ {
+ new_value = enable_grab_baked_texture( (void*)BAKED_UPPER );
+ }
+ else if ("lower" == texture_type)
+ {
+ new_value = enable_grab_baked_texture( (void*)BAKED_LOWER );
+ }
+ else if ("skirt" == texture_type)
+ {
+ new_value = enable_grab_baked_texture( (void*)BAKED_SKIRT );
+ }
+ else if ("hair" == texture_type)
+ {
+ new_value = enable_grab_baked_texture( (void*)BAKED_HAIR );
+ }
+
+ return new_value;
+}
+};
+
+///////////////////////
+// APPEARANCE TO XML //
+///////////////////////
+
+
+class LLAdvancedAppearanceToXML : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar::dumpArchetypeXML(NULL);
+ return true;
+ }
+};
+
+
+
+///////////////////////////////
+// TOGGLE CHARACTER GEOMETRY //
+///////////////////////////////
+
+
+class LLAdvancedToggleCharacterGeometry : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_god_request_avatar_geometry(NULL);
+ return true;
+}
+};
+
+
+ /////////////////////////////
+// TEST MALE / TEST FEMALE //
+/////////////////////////////
+
+class LLAdvancedTestMale : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_test_male(NULL);
+ return true;
+ }
+};
+
+
+class LLAdvancedTestFemale : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_test_female(NULL);
+ return true;
+ }
+};
+
+
+
+///////////////
+// TOGGLE PG //
+///////////////
+
+
+class LLAdvancedTogglePG : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_toggle_pg(NULL);
+ return true;
+ }
+};
+
+
+class LLAdvancedForceParamsToDefault : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLAgent::clearVisualParams(NULL);
+ return true;
+ }
+};
+
+
+
+//////////////////////////
+// RELOAD VERTEX SHADER //
+//////////////////////////
+
+
+class LLAdvancedReloadVertexShader : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ reload_vertex_shader(NULL);
+ return true;
+ }
+};
+
+
+
+////////////////////
+// ANIMATION INFO //
+////////////////////
+
+
+class LLAdvancedToggleAnimationInfo : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar::sShowAnimationDebug = !(LLVOAvatar::sShowAnimationDebug);
+ return true;
+ }
+};
+
+class LLAdvancedCheckAnimationInfo : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLVOAvatar::sShowAnimationDebug;
+ return new_value;
+ }
+};
+
+
+//////////////////
+// SHOW LOOK AT //
+//////////////////
+
+
+class LLAdvancedToggleShowLookAt : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLHUDEffectLookAt::sDebugLookAt = !(LLHUDEffectLookAt::sDebugLookAt);
+ return true;
+ }
+};
+
+class LLAdvancedCheckShowLookAt : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLHUDEffectLookAt::sDebugLookAt;
+ return new_value;
+ }
+};
+
+
+
+///////////////////
+// SHOW POINT AT //
+///////////////////
+
+
+class LLAdvancedToggleShowPointAt : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLHUDEffectPointAt::sDebugPointAt = !(LLHUDEffectPointAt::sDebugPointAt);
+ return true;
+ }
+};
+
+class LLAdvancedCheckShowPointAt : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLHUDEffectPointAt::sDebugPointAt;
+ return new_value;
+ }
+};
+
+
+
+/////////////////////////
+// DEBUG JOINT UPDATES //
+/////////////////////////
+
+
+class LLAdvancedToggleDebugJointUpdates : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar::sJointDebug = !(LLVOAvatar::sJointDebug);
+ return true;
+ }
+};
+
+class LLAdvancedCheckDebugJointUpdates : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLVOAvatar::sJointDebug;
+ return new_value;
+ }
+};
+
+
+
+/////////////////
+// DISABLE LOD //
+/////////////////
+
+
+class LLAdvancedToggleDisableLOD : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLViewerJoint::sDisableLOD = !(LLViewerJoint::sDisableLOD);
+ return true;
+ }
+};
+
+class LLAdvancedCheckDisableLOD : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLViewerJoint::sDisableLOD;
+ return new_value;
+ }
+};
+
+
+
+/////////////////////////
+// DEBUG CHARACTER VIS //
+/////////////////////////
+
+
+class LLAdvancedToggleDebugCharacterVis : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar::sDebugInvisible = !(LLVOAvatar::sDebugInvisible);
+ return true;
+ }
+};
+
+class LLAdvancedCheckDebugCharacterVis : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLVOAvatar::sDebugInvisible;
+ return new_value;
+ }
+};
+
+
+//////////////////////
+// DUMP ATTACHMENTS //
+//////////////////////
+
+
+class LLAdvancedDumpAttachments : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_dump_attachments(NULL);
+ return true;
+ }
+};
+
+
+
+/////////////////////
+// REBAKE TEXTURES //
+/////////////////////
+
+
+class LLAdvancedRebakeTextures : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_rebake_textures(NULL);
+ return true;
+ }
+};
+
+
+#if 1 //ndef LL_RELEASE_FOR_DOWNLOAD
+///////////////////////////
+// DEBUG AVATAR TEXTURES //
+///////////////////////////
+
+
+class LLAdvancedDebugAvatarTextures : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if (gAgent.isGodlike())
+ {
+ handle_debug_avatar_textures(NULL);
+ }
+ return true;
+ }
+};
+
+////////////////////////////////
+// DUMP AVATAR LOCAL TEXTURES //
+////////////////////////////////
+
+
+class LLAdvancedDumpAvatarLocalTextures : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+ handle_dump_avatar_local_textures(NULL);
+#endif
+ return true;
+ }
+};
+
+#endif
+
+/////////////////
+// MESSAGE LOG //
+/////////////////
+
+
+class LLAdvancedEnableMessageLog : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_viewer_enable_message_log(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedDisableMessageLog : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_viewer_disable_message_log(NULL);
+ return true;
+ }
+};
+
+/////////////////
+// DROP PACKET //
+/////////////////
+
+
+class LLAdvancedDropPacket : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gMessageSystem->mPacketRing.dropPackets(1);
+ return true;
+ }
+};
+
+
+
+/////////////////
+// AGENT PILOT //
+/////////////////
+
+
+class LLAdvancedAgentPilot : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string command = userdata.asString();
+ if ("start playback" == command)
+ {
+ LLAgentPilot::startPlayback(NULL);
+ }
+ else if ("stop playback" == command)
+ {
+ LLAgentPilot::stopPlayback(NULL);
+ }
+ else if ("start record" == command)
+ {
+ LLAgentPilot::startRecord(NULL);
+ }
+ else if ("stop record" == command)
+ {
+ LLAgentPilot::saveRecord(NULL);
+ }
+
+ return true;
+ }
+};
+
+
+
+//////////////////////
+// AGENT PILOT LOOP //
+//////////////////////
+
+
+class LLAdvancedToggleAgentPilotLoop : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLAgentPilot::sLoop = !(LLAgentPilot::sLoop);
+ return true;
+ }
+};
+
+class LLAdvancedCheckAgentPilotLoop : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLAgentPilot::sLoop;
+ return new_value;
+ }
+};
+
+
+/////////////////////////
+// SHOW OBJECT UPDATES //
+/////////////////////////
+
+
+class LLAdvancedToggleShowObjectUpdates : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gShowObjectUpdates = !(gShowObjectUpdates);
+ return true;
+ }
+};
+
+class LLAdvancedCheckShowObjectUpdates : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gShowObjectUpdates;
+ return new_value;
+ }
+};
+
+
+
+////////////////////
+// COMPRESS IMAGE //
+////////////////////
+
+
+class LLAdvancedCompressImage : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_compress_image(NULL);
+ return true;
+ }
+};
+
+
+
+/////////////////////////
+// SHOW DEBUG SETTINGS //
+/////////////////////////
+
+
+class LLAdvancedShowDebugSettings : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLFloaterReg::showInstance("settings_debug",userdata);
+ return true;
+ }
+};
+
+
+
+////////////////////////
+// VIEW ADMIN OPTIONS //
+////////////////////////
+
+class LLAdvancedEnableViewAdminOptions : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ // Don't enable in god mode since the admin menu is shown anyway.
+ // Only enable if the user has set the appropriate debug setting.
+ bool new_value = !gAgent.getAgentAccess().isGodlikeWithoutAdminMenuFakery() && gSavedSettings.getBOOL("AdminMenu");
+ return new_value;
+ }
+};
+
+class LLAdvancedToggleViewAdminOptions : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_admin_override_toggle(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedCheckViewAdminOptions : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = check_admin_override(NULL) || gAgent.isGodlike();
+ return new_value;
+ }
+};
+
+/////////////////////////////////////
+// Enable Object Object Occlusion ///
+/////////////////////////////////////
+class LLAdvancedEnableObjectObjectOcclusion: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+
+ bool new_value = gGLManager.mHasOcclusionQuery; // && LLFeatureManager::getInstance()->isFeatureAvailable(userdata.asString());
+ return new_value;
+}
+};
+
+/////////////////////////////////////
+// Enable Framebuffer Objects ///
+/////////////////////////////////////
+class LLAdvancedEnableRenderFBO: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gGLManager.mHasFramebufferObject;
+ return new_value;
+ }
+};
+
+/////////////////////////////////////
+// Enable Deferred Rendering ///
+/////////////////////////////////////
+class LLAdvancedEnableRenderDeferred: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gSavedSettings.getBOOL("RenderUseFBO") && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT > 0) &&
+ LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) > 0;
+ return new_value;
+ }
+};
+
+/////////////////////////////////////
+// Enable Deferred Rendering sub-options
+/////////////////////////////////////
+class LLAdvancedEnableRenderDeferredOptions: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gSavedSettings.getBOOL("RenderUseFBO") && gSavedSettings.getBOOL("RenderDeferred");
+ return new_value;
+ }
+};
+
+
+
+//////////////////
+// ADMIN STATUS //
+//////////////////
+
+
+class LLAdvancedRequestAdminStatus : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_god_mode(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedLeaveAdminStatus : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_leave_god_mode(NULL);
+ return true;
+ }
+};
+
+//////////////////////////
+// Advanced > Debugging //
+//////////////////////////
+
+
+class LLAdvancedForceErrorBreakpoint : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ force_error_breakpoint(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedForceErrorLlerror : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ force_error_llerror(NULL);
+ return true;
+ }
+};
+class LLAdvancedForceErrorBadMemoryAccess : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ force_error_bad_memory_access(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedForceErrorInfiniteLoop : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ force_error_infinite_loop(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedForceErrorSoftwareException : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ force_error_software_exception(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedForceErrorDriverCrash : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ force_error_driver_crash(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedForceErrorDisconnectViewer : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_disconnect_viewer(NULL);
+ return true;
+}
+};
+
+
+#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
+
+class LLAdvancedHandleToggleHackedGodmode : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_toggle_hacked_godmode(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedCheckToggleHackedGodmode : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ check_toggle_hacked_godmode(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedEnableToggleHackedGodmode : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = enable_toggle_hacked_godmode(NULL);
+ return new_value;
+ }
+};
+#endif
+
+
+//
+////-------------------------------------------------------------------
+//// Advanced menu
+////-------------------------------------------------------------------
+
+//////////////////
+// ADMIN MENU //
+//////////////////
+
+// Admin > Object
+class LLAdminForceTakeCopy : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ force_take_copy(NULL);
+ return true;
+ }
+};
+
+class LLAdminHandleObjectOwnerSelf : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_object_owner_self(NULL);
+ return true;
+ }
+};
+class LLAdminHandleObjectOwnerPermissive : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_object_owner_permissive(NULL);
+ return true;
+ }
+};
+
+class LLAdminHandleForceDelete : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_force_delete(NULL);
+ return true;
+ }
+};
+
+class LLAdminHandleObjectLock : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_object_lock(NULL);
+ return true;
+ }
+};
+
+class LLAdminHandleObjectAssetIDs: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_object_asset_ids(NULL);
+ return true;
+ }
+};
+
+//Admin >Parcel
+class LLAdminHandleForceParcelOwnerToMe: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_force_parcel_owner_to_me(NULL);
+ return true;
+ }
+};
+class LLAdminHandleForceParcelToContent: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_force_parcel_to_content(NULL);
+ return true;
+ }
+};
+class LLAdminHandleClaimPublicLand: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_claim_public_land(NULL);
+ return true;
+ }
+};
+
+// Admin > Region
+class LLAdminHandleRegionDumpTempAssetData: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_region_dump_temp_asset_data(NULL);
+ return true;
+ }
+};
+//Admin (Top Level)
+
+class LLAdminOnSaveState: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLPanelRegionTools::onSaveState(NULL);
+ return true;
+}
+};
+
+
+//-----------------------------------------------------------------------------
+// cleanup_menus()
+//-----------------------------------------------------------------------------
+void cleanup_menus()
+{
+ delete gMenuParcelObserver;
+ gMenuParcelObserver = NULL;
+
+ delete gMenuAvatarSelf;
+ gMenuAvatarSelf = NULL;
+
+ delete gMenuAvatarOther;
+ gMenuAvatarOther = NULL;
+
+ delete gMenuObject;
+ gMenuObject = NULL;
+
+ delete gMenuAttachmentSelf;
+ gMenuAttachmentSelf = NULL;
+
+ delete gMenuAttachmentOther;
+ gMenuAttachmentSelf = NULL;
+
+ delete gMenuLand;
+ gMenuLand = NULL;
+
+ delete gMenuBarView;
+ gMenuBarView = NULL;
+
+ delete gPopupMenuView;
+ gPopupMenuView = NULL;
+
+ delete gMenuHolder;
+ gMenuHolder = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Object pie menu
+//-----------------------------------------------------------------------------
+
+class LLObjectReportAbuse : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ if (objectp)
+ {
+ LLFloaterReporter::showFromObject(objectp->getID());
+ }
+ return true;
+ }
+};
+
+// Enabled it you clicked an object
+class LLObjectEnableReportAbuse : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLSelectMgr::getInstance()->getSelection()->getObjectCount() != 0;
+ return new_value;
+ }
+};
+
+void handle_object_touch()
+{
+ LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ if (!object) return;
+
+ LLPickInfo pick = LLToolPie::getInstance()->getPick();
+
+ LLMessageSystem *msg = gMessageSystem;
+
+ msg->newMessageFast(_PREHASH_ObjectGrab);
+ msg->nextBlockFast( _PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast( _PREHASH_ObjectData);
+ msg->addU32Fast( _PREHASH_LocalID, object->mLocalID);
+ msg->addVector3Fast(_PREHASH_GrabOffset, LLVector3::zero );
+ msg->nextBlock("SurfaceInfo");
+ msg->addVector3("UVCoord", LLVector3(pick.mUVCoords));
+ msg->addVector3("STCoord", LLVector3(pick.mSTCoords));
+ msg->addS32Fast(_PREHASH_FaceIndex, pick.mObjectFace);
+ msg->addVector3("Position", pick.mIntersection);
+ msg->addVector3("Normal", pick.mNormal);
+ msg->addVector3("Binormal", pick.mBinormal);
+ msg->sendMessage( object->getRegion()->getHost());
+
+ // *NOTE: Hope the packets arrive safely and in order or else
+ // there will be some problems.
+ // *TODO: Just fix this bad assumption.
+ msg->newMessageFast(_PREHASH_ObjectDeGrab);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_ObjectData);
+ msg->addU32Fast(_PREHASH_LocalID, object->mLocalID);
+ msg->nextBlock("SurfaceInfo");
+ msg->addVector3("UVCoord", LLVector3(pick.mUVCoords));
+ msg->addVector3("STCoord", LLVector3(pick.mSTCoords));
+ msg->addS32Fast(_PREHASH_FaceIndex, pick.mObjectFace);
+ msg->addVector3("Position", pick.mIntersection);
+ msg->addVector3("Normal", pick.mNormal);
+ msg->addVector3("Binormal", pick.mBinormal);
+ msg->sendMessage(object->getRegion()->getHost());
+}
+
+static void init_default_item_label(const std::string& item_name)
+{
+ boost::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name);
+ if (it == sDefaultItemLabels.end())
+ {
+ // *NOTE: This will not work for items of type LLMenuItemCheckGL because they return boolean value
+ // (doesn't seem to matter much ATM).
+ LLStringExplicit default_label = gMenuHolder->childGetValue(item_name).asString();
+ if (!default_label.empty())
+ {
+ sDefaultItemLabels.insert(std::pair<std::string, LLStringExplicit>(item_name, default_label));
+ }
+ }
+}
+
+static LLStringExplicit get_default_item_label(const std::string& item_name)
+{
+ LLStringExplicit res("");
+ boost::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name);
+ if (it != sDefaultItemLabels.end())
+ {
+ res = it->second;
+ }
+
+ return res;
+}
+
+
+bool enable_object_touch(LLUICtrl* ctrl)
+{
+ LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+
+ bool new_value = obj && obj->flagHandleTouch();
+
+ std::string item_name = ctrl->getName();
+ init_default_item_label(item_name);
+
+ // Update label based on the node touch name if available.
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
+ if (node && node->mValid && !node->mTouchName.empty())
+ {
+ gMenuHolder->childSetText(item_name, node->mTouchName);
+ }
+ else
+ {
+ gMenuHolder->childSetText(item_name, get_default_item_label(item_name));
+ }
+
+ return new_value;
+};
+
+//void label_touch(std::string& label, void*)
+//{
+// LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
+// if (node && node->mValid && !node->mTouchName.empty())
+// {
+// label.assign(node->mTouchName);
+// }
+// else
+// {
+// label.assign("Touch");
+// }
+//}
+
+void handle_object_open()
+{
+ LLFloaterReg::showInstance("openobject");
+}
+
+bool enable_object_open()
+{
+ // Look for contents in root object, which is all the LLFloaterOpenObject
+ // understands.
+ LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ if (!obj) return false;
+
+ LLViewerObject* root = obj->getRootEdit();
+ if (!root) return false;
+
+ return root->allowOpen();
+}
+
+
+class LLViewJoystickFlycam : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_toggle_flycam();
+ return true;
+ }
+};
+
+class LLViewCheckJoystickFlycam : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLViewerJoystick::getInstance()->getOverrideCamera();
+ return new_value;
+ }
+};
+
+void handle_toggle_flycam()
+{
+ LLViewerJoystick::getInstance()->toggleFlycam();
+}
+
+class LLObjectBuild : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") )
+ {
+ // zoom in if we're looking at the avatar
+ gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);
+ gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick());
+ gAgentCamera.cameraZoomIn(0.666f);
+ gAgentCamera.cameraOrbitOver( 30.f * DEG_TO_RAD );
+ gViewerWindow->moveCursorToCenter();
+ }
+ else if ( gSavedSettings.getBOOL("EditCameraMovement") )
+ {
+ gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick());
+ gViewerWindow->moveCursorToCenter();
+ }
+
+ LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
+ LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompCreate::getInstance() );
+
+ // Could be first use
+ //LLFirstUse::useBuild();
+ return true;
+ }
+};
+
+
+void handle_object_edit()
+{
+ LLViewerParcelMgr::getInstance()->deselectLand();
+
+ if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit())
+ {
+ LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+
+ if (selection->getSelectType() == SELECT_TYPE_HUD || !gSavedSettings.getBOOL("EditCameraMovement"))
+ {
+ // always freeze camera in space, even if camera doesn't move
+ // so, for example, follow cam scripts can't affect you when in build mode
+ gAgentCamera.setFocusGlobal(gAgentCamera.calcFocusPositionTargetGlobal(), LLUUID::null);
+ gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);
+ }
+ else
+ {
+ gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);
+ LLViewerObject* selected_objectp = selection->getFirstRootObject();
+ if (selected_objectp)
+ {
+ // zoom in on object center instead of where we clicked, as we need to see the manipulator handles
+ gAgentCamera.setFocusGlobal(selected_objectp->getPositionGlobal(), selected_objectp->getID());
+ gAgentCamera.cameraZoomIn(0.666f);
+ gAgentCamera.cameraOrbitOver( 30.f * DEG_TO_RAD );
+ gViewerWindow->moveCursorToCenter();
+ }
+ }
+ }
+
+ LLFloaterReg::showInstance("build");
+
+ LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
+ gFloaterTools->setEditTool( LLToolCompTranslate::getInstance() );
+
+ LLViewerJoystick::getInstance()->moveObjects(true);
+ LLViewerJoystick::getInstance()->setNeedsReset(true);
+
+ // Could be first use
+ //LLFirstUse::useBuild();
+ return;
+}
+
+void handle_object_inspect()
+{
+ LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+ LLViewerObject* selected_objectp = selection->getFirstRootObject();
+ if (selected_objectp)
+ {
+ LLSD key;
+ key["task"] = "task";
+ LLSideTray::getInstance()->showPanel("sidepanel_inventory", key);
+ }
+
+ /*
+ // Old floater properties
+ LLFloaterReg::showInstance("inspect", LLSD());
+ */
+}
+
+//---------------------------------------------------------------------------
+// Land pie menu
+//---------------------------------------------------------------------------
+class LLLandBuild : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLViewerParcelMgr::getInstance()->deselectLand();
+
+ if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") )
+ {
+ // zoom in if we're looking at the avatar
+ gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);
+ gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick());
+ gAgentCamera.cameraZoomIn(0.666f);
+ gAgentCamera.cameraOrbitOver( 30.f * DEG_TO_RAD );
+ gViewerWindow->moveCursorToCenter();
+ }
+ else if ( gSavedSettings.getBOOL("EditCameraMovement") )
+ {
+ // otherwise just move focus
+ gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick());
+ gViewerWindow->moveCursorToCenter();
+ }
+
+
+ LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
+ LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompCreate::getInstance() );
+
+ // Could be first use
+ //LLFirstUse::useBuild();
+ return true;
+ }
+};
+
+class LLLandBuyPass : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLPanelLandGeneral::onClickBuyPass((void *)FALSE);
+ return true;
+ }
+};
+
+class LLLandEnableBuyPass : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLPanelLandGeneral::enableBuyPass(NULL);
+ return new_value;
+ }
+};
+
+// BUG: Should really check if CLICK POINT is in a parcel where you can build.
+BOOL enable_land_build(void*)
+{
+ if (gAgent.isGodlike()) return TRUE;
+ if (gAgent.inPrelude()) return FALSE;
+
+ BOOL can_build = FALSE;
+ LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+ if (agent_parcel)
+ {
+ can_build = agent_parcel->getAllowModify();
+ }
+ return can_build;
+}
+
+// BUG: Should really check if OBJECT is in a parcel where you can build.
+BOOL enable_object_build(void*)
+{
+ if (gAgent.isGodlike()) return TRUE;
+ if (gAgent.inPrelude()) return FALSE;
+
+ BOOL can_build = FALSE;
+ LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+ if (agent_parcel)
+ {
+ can_build = agent_parcel->getAllowModify();
+ }
+ return can_build;
+}
+
+bool enable_object_edit()
+{
+ // *HACK: The new "prelude" Help Islands have a build sandbox area,
+ // so users need the Edit and Create pie menu options when they are
+ // there. Eventually this needs to be replaced with code that only
+ // lets you edit objects if you have permission to do so (edit perms,
+ // group edit, god). See also lltoolbar.cpp. JC
+ bool enable = false;
+ if (gAgent.inPrelude())
+ {
+ enable = LLViewerParcelMgr::getInstance()->allowAgentBuild()
+ || LLSelectMgr::getInstance()->getSelection()->isAttachment();
+ }
+ else if (LLSelectMgr::getInstance()->selectGetAllValidAndObjectsFound())
+ {
+ enable = true;
+ }
+
+ return enable;
+}
+
+// mutually exclusive - show either edit option or build in menu
+bool enable_object_build()
+{
+ return !enable_object_edit();
+}
+
+class LLSelfRemoveAllAttachments : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLAgentWearables::userRemoveAllAttachments();
+ return true;
+ }
+};
+
+class LLSelfEnableRemoveAllAttachments : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = false;
+ if (isAgentAvatarValid())
+ {
+ for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
+ iter != gAgentAvatarp->mAttachmentPoints.end(); )
+ {
+ LLVOAvatar::attachment_map_t::iterator curiter = iter++;
+ LLViewerJointAttachment* attachment = curiter->second;
+ if (attachment->getNumObjects() > 0)
+ {
+ new_value = true;
+ break;
+ }
+ }
+ }
+ return new_value;
+ }
+};
+
+BOOL enable_has_attachments(void*)
+{
+
+ return FALSE;
+}
+
+//---------------------------------------------------------------------------
+// Avatar pie menu
+//---------------------------------------------------------------------------
+//void handle_follow(void *userdata)
+//{
+// // follow a given avatar by ID
+// LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+// if (objectp)
+// {
+// gAgent.startFollowPilot(objectp->getID());
+// }
+//}
+
+bool enable_object_mute()
+{
+ LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ if (!object) return false;
+
+ LLVOAvatar* avatar = find_avatar_from_object(object);
+ if (avatar)
+ {
+ // It's an avatar
+ LLNameValue *lastname = avatar->getNVPair("LastName");
+ bool is_linden =
+ lastname && !LLStringUtil::compareStrings(lastname->getString(), "Linden");
+ bool is_self = avatar->isSelf();
+ return !is_linden && !is_self;
+ }
+ else
+ {
+ // Just a regular object
+ return LLSelectMgr::getInstance()->getSelection()->
+ contains( object, SELECT_ALL_TES );
+ }
+}
+
+class LLObjectMute : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ if (!object) return true;
+
+ LLUUID id;
+ std::string name;
+ LLMute::EType type;
+ LLVOAvatar* avatar = find_avatar_from_object(object);
+ if (avatar)
+ {
+ id = avatar->getID();
+
+ LLNameValue *firstname = avatar->getNVPair("FirstName");
+ LLNameValue *lastname = avatar->getNVPair("LastName");
+ if (firstname && lastname)
+ {
+ name = LLCacheName::buildFullName(
+ firstname->getString(), lastname->getString());
+ }
+
+ type = LLMute::AGENT;
+ }
+ else
+ {
+ // it's an object
+ id = object->getID();
+
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
+ if (node)
+ {
+ name = node->mName;
+ }
+
+ type = LLMute::OBJECT;
+ }
+
+ LLMute mute(id, name, type);
+ if (LLMuteList::getInstance()->isMuted(mute.mID))
+ {
+ LLMuteList::getInstance()->remove(mute);
+ }
+ else
+ {
+ LLMuteList::getInstance()->add(mute);
+ LLPanelBlockedList::showPanelAndSelect(mute.mID);
+ }
+
+ return true;
+ }
+};
+
+bool handle_go_to()
+{
+ // try simulator autopilot
+ std::vector<std::string> strings;
+ std::string val;
+ LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal;
+ val = llformat("%g", pos.mdV[VX]);
+ strings.push_back(val);
+ val = llformat("%g", pos.mdV[VY]);
+ strings.push_back(val);
+ val = llformat("%g", pos.mdV[VZ]);
+ strings.push_back(val);
+ send_generic_message("autopilot", strings);
+
+ LLViewerParcelMgr::getInstance()->deselectLand();
+
+ if (isAgentAvatarValid() && !gSavedSettings.getBOOL("AutoPilotLocksCamera"))
+ {
+ gAgentCamera.setFocusGlobal(gAgentCamera.getFocusTargetGlobal(), gAgentAvatarp->getID());
+ }
+ else
+ {
+ // Snap camera back to behind avatar
+ gAgentCamera.setFocusOnAvatar(TRUE, ANIMATE);
+ }
+
+ // Could be first use
+ //LLFirstUse::useGoTo();
+ return true;
+}
+
+class LLGoToObject : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return handle_go_to();
+ }
+};
+
+class LLAvatarReportAbuse : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
+ if(avatar)
+ {
+ LLFloaterReporter::showFromObject(avatar->getID());
+ }
+ return true;
+ }
+};
+
+
+//---------------------------------------------------------------------------
+// Parcel freeze, eject, etc.
+//---------------------------------------------------------------------------
+bool callback_freeze(const LLSD& notification, const LLSD& response)
+{
+ LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID();
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+
+ if (0 == option || 1 == option)
+ {
+ U32 flags = 0x0;
+ if (1 == option)
+ {
+ // unfreeze
+ flags |= 0x1;
+ }
+
+ LLMessageSystem* msg = gMessageSystem;
+ LLViewerObject* avatar = gObjectList.findObject(avatar_id);
+
+ if (avatar)
+ {
+ msg->newMessage("FreezeUser");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID", gAgent.getID());
+ msg->addUUID("SessionID", gAgent.getSessionID());
+ msg->nextBlock("Data");
+ msg->addUUID("TargetID", avatar_id );
+ msg->addU32("Flags", flags );
+ msg->sendReliable( avatar->getRegion()->getHost() );
+ }
+ }
+ return false;
+}
+
+
+void handle_avatar_freeze(const LLSD& avatar_id)
+{
+ // Use avatar_id if available, otherwise default to right-click avatar
+ LLVOAvatar* avatar = NULL;
+ if (avatar_id.asUUID().notNull())
+ {
+ avatar = find_avatar_from_object(avatar_id.asUUID());
+ }
+ else
+ {
+ avatar = find_avatar_from_object(
+ LLSelectMgr::getInstance()->getSelection()->getPrimaryObject());
+ }
+
+ if( avatar )
+ {
+ std::string fullname = avatar->getFullname();
+ LLSD payload;
+ payload["avatar_id"] = avatar->getID();
+
+ if (!fullname.empty())
+ {
+ LLSD args;
+ args["AVATAR_NAME"] = fullname;
+ LLNotificationsUtil::add("FreezeAvatarFullname",
+ args,
+ payload,
+ callback_freeze);
+ }
+ else
+ {
+ LLNotificationsUtil::add("FreezeAvatar",
+ LLSD(),
+ payload,
+ callback_freeze);
+ }
+ }
+}
+
+class LLAvatarVisibleDebug : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return gAgent.isGodlike();
+ }
+};
+
+class LLAvatarDebug : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
+ if( avatar )
+ {
+ if (avatar->isSelf())
+ {
+ ((LLVOAvatarSelf *)avatar)->dumpLocalTextures();
+ }
+ llinfos << "Dumping temporary asset data to simulator logs for avatar " << avatar->getID() << llendl;
+ std::vector<std::string> strings;
+ strings.push_back(avatar->getID().asString());
+ LLUUID invoice;
+ send_generic_message("dumptempassetdata", strings, invoice);
+ LLFloaterReg::showInstance( "avatar_textures", LLSD(avatar->getID()) );
+ }
+ return true;
+ }
+};
+
+bool callback_eject(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (2 == option)
+ {
+ // Cancel button.
+ return false;
+ }
+ LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID();
+ bool ban_enabled = notification["payload"]["ban_enabled"].asBoolean();
+
+ if (0 == option)
+ {
+ // Eject button
+ LLMessageSystem* msg = gMessageSystem;
+ LLViewerObject* avatar = gObjectList.findObject(avatar_id);
+
+ if (avatar)
+ {
+ U32 flags = 0x0;
+ msg->newMessage("EjectUser");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID", gAgent.getID() );
+ msg->addUUID("SessionID", gAgent.getSessionID() );
+ msg->nextBlock("Data");
+ msg->addUUID("TargetID", avatar_id );
+ msg->addU32("Flags", flags );
+ msg->sendReliable( avatar->getRegion()->getHost() );
+ }
+ }
+ else if (ban_enabled)
+ {
+ // This is tricky. It is similar to say if it is not an 'Eject' button,
+ // and it is also not an 'Cancle' button, and ban_enabled==ture,
+ // it should be the 'Eject and Ban' button.
+ LLMessageSystem* msg = gMessageSystem;
+ LLViewerObject* avatar = gObjectList.findObject(avatar_id);
+
+ if (avatar)
+ {
+ U32 flags = 0x1;
+ msg->newMessage("EjectUser");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID", gAgent.getID() );
+ msg->addUUID("SessionID", gAgent.getSessionID() );
+ msg->nextBlock("Data");
+ msg->addUUID("TargetID", avatar_id );
+ msg->addU32("Flags", flags );
+ msg->sendReliable( avatar->getRegion()->getHost() );
+ }
+ }
+ return false;
+}
+
+void handle_avatar_eject(const LLSD& avatar_id)
+{
+ // Use avatar_id if available, otherwise default to right-click avatar
+ LLVOAvatar* avatar = NULL;
+ if (avatar_id.asUUID().notNull())
+ {
+ avatar = find_avatar_from_object(avatar_id.asUUID());
+ }
+ else
+ {
+ avatar = find_avatar_from_object(
+ LLSelectMgr::getInstance()->getSelection()->getPrimaryObject());
+ }
+
+ if( avatar )
+ {
+ LLSD payload;
+ payload["avatar_id"] = avatar->getID();
+ std::string fullname = avatar->getFullname();
+
+ const LLVector3d& pos = avatar->getPositionGlobal();
+ LLParcel* parcel = LLViewerParcelMgr::getInstance()->selectParcelAt(pos)->getParcel();
+
+ if (LLViewerParcelMgr::getInstance()->isParcelOwnedByAgent(parcel,GP_LAND_MANAGE_BANNED))
+ {
+ payload["ban_enabled"] = true;
+ if (!fullname.empty())
+ {
+ LLSD args;
+ args["AVATAR_NAME"] = fullname;
+ LLNotificationsUtil::add("EjectAvatarFullname",
+ args,
+ payload,
+ callback_eject);
+ }
+ else
+ {
+ LLNotificationsUtil::add("EjectAvatarFullname",
+ LLSD(),
+ payload,
+ callback_eject);
+ }
+ }
+ else
+ {
+ payload["ban_enabled"] = false;
+ if (!fullname.empty())
+ {
+ LLSD args;
+ args["AVATAR_NAME"] = fullname;
+ LLNotificationsUtil::add("EjectAvatarFullnameNoBan",
+ args,
+ payload,
+ callback_eject);
+ }
+ else
+ {
+ LLNotificationsUtil::add("EjectAvatarNoBan",
+ LLSD(),
+ payload,
+ callback_eject);
+ }
+ }
+ }
+}
+
+bool enable_freeze_eject(const LLSD& avatar_id)
+{
+ // Use avatar_id if available, otherwise default to right-click avatar
+ LLVOAvatar* avatar = NULL;
+ if (avatar_id.asUUID().notNull())
+ {
+ avatar = find_avatar_from_object(avatar_id.asUUID());
+ }
+ else
+ {
+ avatar = find_avatar_from_object(
+ LLSelectMgr::getInstance()->getSelection()->getPrimaryObject());
+ }
+ if (!avatar) return false;
+
+ // Gods can always freeze
+ if (gAgent.isGodlike()) return true;
+
+ // Estate owners / managers can freeze
+ // Parcel owners can also freeze
+ const LLVector3& pos = avatar->getPositionRegion();
+ const LLVector3d& pos_global = avatar->getPositionGlobal();
+ LLParcel* parcel = LLViewerParcelMgr::getInstance()->selectParcelAt(pos_global)->getParcel();
+ LLViewerRegion* region = avatar->getRegion();
+ if (!region) return false;
+
+ bool new_value = region->isOwnedSelf(pos);
+ if (!new_value || region->isOwnedGroup(pos))
+ {
+ new_value = LLViewerParcelMgr::getInstance()->isParcelOwnedByAgent(parcel,GP_LAND_ADMIN);
+ }
+ return new_value;
+}
+
+
+void login_done(S32 which, void *user)
+{
+ llinfos << "Login done " << which << llendl;
+
+ LLPanelLogin::closePanel();
+}
+
+
+bool callback_leave_group(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option == 0)
+ {
+ LLMessageSystem *msg = gMessageSystem;
+
+ msg->newMessageFast(_PREHASH_LeaveGroupRequest);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_GroupData);
+ msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID() );
+ gAgent.sendReliableMessage();
+ }
+ return false;
+}
+
+void append_aggregate(std::string& string, const LLAggregatePermissions& ag_perm, PermissionBit bit, const char* txt)
+{
+ LLAggregatePermissions::EValue val = ag_perm.getValue(bit);
+ std::string buffer;
+ switch(val)
+ {
+ case LLAggregatePermissions::AP_NONE:
+ buffer = llformat( "* %s None\n", txt);
+ break;
+ case LLAggregatePermissions::AP_SOME:
+ buffer = llformat( "* %s Some\n", txt);
+ break;
+ case LLAggregatePermissions::AP_ALL:
+ buffer = llformat( "* %s All\n", txt);
+ break;
+ case LLAggregatePermissions::AP_EMPTY:
+ default:
+ break;
+ }
+ string.append(buffer);
+}
+
+bool enable_buy_object()
+{
+ // In order to buy, there must only be 1 purchaseable object in
+ // the selection manger.
+ if(LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() != 1) return false;
+ LLViewerObject* obj = NULL;
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
+ if(node)
+ {
+ obj = node->getObject();
+ if(!obj) return false;
+
+ if( for_sale_selection(node) )
+ {
+ // *NOTE: Is this needed? This checks to see if anyone owns the
+ // object, dating back to when we had "public" objects owned by
+ // no one. JC
+ if(obj->permAnyOwner()) return true;
+ }
+ }
+ return false;
+}
+
+// Note: This will only work if the selected object's data has been
+// received by the viewer and cached in the selection manager.
+void handle_buy_object(LLSaleInfo sale_info)
+{
+ if(!LLSelectMgr::getInstance()->selectGetAllRootsValid())
+ {
+ LLNotificationsUtil::add("UnableToBuyWhileDownloading");
+ return;
+ }
+
+ LLUUID owner_id;
+ std::string owner_name;
+ BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name);
+ if (!owners_identical)
+ {
+ LLNotificationsUtil::add("CannotBuyObjectsFromDifferentOwners");
+ return;
+ }
+
+ LLPermissions perm;
+ BOOL valid = LLSelectMgr::getInstance()->selectGetPermissions(perm);
+ LLAggregatePermissions ag_perm;
+ valid &= LLSelectMgr::getInstance()->selectGetAggregatePermissions(ag_perm);
+ if(!valid || !sale_info.isForSale() || !perm.allowTransferTo(gAgent.getID()))
+ {
+ LLNotificationsUtil::add("ObjectNotForSale");
+ return;
+ }
+
+ LLFloaterBuy::show(sale_info);
+}
+
+
+void handle_buy_contents(LLSaleInfo sale_info)
+{
+ LLFloaterBuyContents::show(sale_info);
+}
+
+void handle_region_dump_temp_asset_data(void*)
+{
+ llinfos << "Dumping temporary asset data to simulator logs" << llendl;
+ std::vector<std::string> strings;
+ LLUUID invoice;
+ send_generic_message("dumptempassetdata", strings, invoice);
+}
+
+void handle_region_clear_temp_asset_data(void*)
+{
+ llinfos << "Clearing temporary asset data" << llendl;
+ std::vector<std::string> strings;
+ LLUUID invoice;
+ send_generic_message("cleartempassetdata", strings, invoice);
+}
+
+void handle_region_dump_settings(void*)
+{
+ LLViewerRegion* regionp = gAgent.getRegion();
+ if (regionp)
+ {
+ llinfos << "Damage: " << (regionp->getAllowDamage() ? "on" : "off") << llendl;
+ llinfos << "Landmark: " << (regionp->getAllowLandmark() ? "on" : "off") << llendl;
+ llinfos << "SetHome: " << (regionp->getAllowSetHome() ? "on" : "off") << llendl;
+ llinfos << "ResetHome: " << (regionp->getResetHomeOnTeleport() ? "on" : "off") << llendl;
+ llinfos << "SunFixed: " << (regionp->getSunFixed() ? "on" : "off") << llendl;
+ llinfos << "BlockFly: " << (regionp->getBlockFly() ? "on" : "off") << llendl;
+ llinfos << "AllowP2P: " << (regionp->getAllowDirectTeleport() ? "on" : "off") << llendl;
+ llinfos << "Water: " << (regionp->getWaterHeight()) << llendl;
+ }
+}
+
+void handle_dump_group_info(void *)
+{
+ gAgent.dumpGroupInfo();
+}
+
+void handle_dump_capabilities_info(void *)
+{
+ LLViewerRegion* regionp = gAgent.getRegion();
+ if (regionp)
+ {
+ regionp->logActiveCapabilities();
+ }
+}
+
+void handle_dump_region_object_cache(void*)
+{
+ LLViewerRegion* regionp = gAgent.getRegion();
+ if (regionp)
+ {
+ regionp->dumpCache();
+ }
+}
+
+void handle_dump_focus()
+{
+ LLUICtrl *ctrl = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());
+
+ llinfos << "Keyboard focus " << (ctrl ? ctrl->getName() : "(none)") << llendl;
+}
+
+class LLSelfStandUp : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gAgent.standUp();
+ return true;
+ }
+};
+
+bool enable_standup_self()
+{
+ return isAgentAvatarValid() && gAgentAvatarp->isSitting();
+}
+
+class LLSelfSitDown : public view_listener_t
+ {
+ bool handleEvent(const LLSD& userdata)
+ {
+ gAgent.sitDown();
+ return true;
+ }
+ };
+
+bool enable_sitdown_self()
+{
+ return isAgentAvatarValid() && !gAgentAvatarp->isSitting() && !gAgent.getFlying();
+}
+
+// Used from the login screen to aid in UI work on side tray
+void handle_show_side_tray()
+{
+ LLSideTray* side_tray = LLSideTray::getInstance();
+ LLView* root = gViewerWindow->getRootView();
+ // automatically removes and re-adds if there already
+ root->addChild(side_tray);
+}
+
+// Toggle one of "People" panel tabs in side tray.
+class LLTogglePanelPeopleTab : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string panel_name = userdata.asString();
+
+ LLSD param;
+ param["people_panel_tab_name"] = panel_name;
+
+ static LLPanel* friends_panel = NULL;
+ static LLPanel* groups_panel = NULL;
+ static LLPanel* nearby_panel = NULL;
+
+ if (panel_name == "friends_panel")
+ {
+ return togglePeoplePanel(friends_panel, panel_name, param);
+ }
+ else if (panel_name == "groups_panel")
+ {
+ return togglePeoplePanel(groups_panel, panel_name, param);
+ }
+ else if (panel_name == "nearby_panel")
+ {
+ return togglePeoplePanel(nearby_panel, panel_name, param);
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ static bool togglePeoplePanel(LLPanel* &panel, const std::string& panel_name, const LLSD& param)
+ {
+ if(!panel)
+ {
+ panel = LLSideTray::getInstance()->getPanel(panel_name);
+ if(!panel)
+ return false;
+ }
+
+ LLSideTray::getInstance()->togglePanel(panel, "panel_people", param);
+
+ return true;
+ }
+};
+
+BOOL check_admin_override(void*)
+{
+ return gAgent.getAdminOverride();
+}
+
+void handle_admin_override_toggle(void*)
+{
+ gAgent.setAdminOverride(!gAgent.getAdminOverride());
+
+ // The above may have affected which debug menus are visible
+ show_debug_menus();
+}
+
+void handle_god_mode(void*)
+{
+ gAgent.requestEnterGodMode();
+}
+
+void handle_leave_god_mode(void*)
+{
+ gAgent.requestLeaveGodMode();
+}
+
+void set_god_level(U8 god_level)
+{
+ U8 old_god_level = gAgent.getGodLevel();
+ gAgent.setGodLevel( god_level );
+ LLViewerParcelMgr::getInstance()->notifyObservers();
+
+ // God mode changes region visibility
+ LLWorldMap::getInstance()->reloadItems(true);
+
+ // inventory in items may change in god mode
+ gObjectList.dirtyAllObjectInventory();
+
+ if(gViewerWindow)
+ {
+ gViewerWindow->setMenuBackgroundColor(god_level > GOD_NOT,
+ LLGridManager::getInstance()->isInProductionGrid());
+ }
+
+ LLSD args;
+ if(god_level > GOD_NOT)
+ {
+ args["LEVEL"] = llformat("%d",(S32)god_level);
+ LLNotificationsUtil::add("EnteringGodMode", args);
+ }
+ else
+ {
+ args["LEVEL"] = llformat("%d",(S32)old_god_level);
+ LLNotificationsUtil::add("LeavingGodMode", args);
+ }
+
+ // changing god-level can affect which menus we see
+ show_debug_menus();
+
+ // changing god-level can invalidate search results
+ LLFloaterSearch *search = dynamic_cast<LLFloaterSearch*>(LLFloaterReg::getInstance("search"));
+ if (search)
+ {
+ search->godLevelChanged(god_level);
+ }
+}
+
+#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
+void handle_toggle_hacked_godmode(void*)
+{
+ gHackGodmode = !gHackGodmode;
+ set_god_level(gHackGodmode ? GOD_MAINTENANCE : GOD_NOT);
+}
+
+BOOL check_toggle_hacked_godmode(void*)
+{
+ return gHackGodmode;
+}
+
+bool enable_toggle_hacked_godmode(void*)
+{
+ return !LLGridManager::getInstance()->isInProductionGrid();
+}
+#endif
+
+void process_grant_godlike_powers(LLMessageSystem* msg, void**)
+{
+ LLUUID agent_id;
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
+ LLUUID session_id;
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id);
+ if((agent_id == gAgent.getID()) && (session_id == gAgent.getSessionID()))
+ {
+ U8 god_level;
+ msg->getU8Fast(_PREHASH_GrantData, _PREHASH_GodLevel, god_level);
+ set_god_level(god_level);
+ }
+ else
+ {
+ llwarns << "Grant godlike for wrong agent " << agent_id << llendl;
+ }
+}
+
+/*
+class LLHaveCallingcard : public LLInventoryCollectFunctor
+{
+public:
+ LLHaveCallingcard(const LLUUID& agent_id);
+ virtual ~LLHaveCallingcard() {}
+ virtual bool operator()(LLInventoryCategory* cat,
+ LLInventoryItem* item);
+ BOOL isThere() const { return mIsThere;}
+protected:
+ LLUUID mID;
+ BOOL mIsThere;
+};
+
+LLHaveCallingcard::LLHaveCallingcard(const LLUUID& agent_id) :
+ mID(agent_id),
+ mIsThere(FALSE)
+{
+}
+
+bool LLHaveCallingcard::operator()(LLInventoryCategory* cat,
+ LLInventoryItem* item)
+{
+ if(item)
+ {
+ if((item->getType() == LLAssetType::AT_CALLINGCARD)
+ && (item->getCreatorUUID() == mID))
+ {
+ mIsThere = TRUE;
+ }
+ }
+ return FALSE;
+}
+*/
+
+BOOL is_agent_mappable(const LLUUID& agent_id)
+{
+ const LLRelationship* buddy_info = NULL;
+ bool is_friend = LLAvatarActions::isFriend(agent_id);
+
+ if (is_friend)
+ buddy_info = LLAvatarTracker::instance().getBuddyInfo(agent_id);
+
+ return (buddy_info &&
+ buddy_info->isOnline() &&
+ buddy_info->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION)
+ );
+}
+
+
+// Enable a menu item when you don't have someone's card.
+class LLAvatarEnableAddFriend : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject());
+ bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID());
+ return new_value;
+ }
+};
+
+void request_friendship(const LLUUID& dest_id)
+{
+ LLViewerObject* dest = gObjectList.findObject(dest_id);
+ if(dest && dest->isAvatar())
+ {
+ std::string full_name;
+ LLNameValue* nvfirst = dest->getNVPair("FirstName");
+ LLNameValue* nvlast = dest->getNVPair("LastName");
+ if(nvfirst && nvlast)
+ {
+ full_name = LLCacheName::buildFullName(
+ nvfirst->getString(), nvlast->getString());
+ }
+ if (!full_name.empty())
+ {
+ LLAvatarActions::requestFriendshipDialog(dest_id, full_name);
+ }
+ else
+ {
+ LLNotificationsUtil::add("CantOfferFriendship");
+ }
+ }
+}
+
+
+class LLEditEnableCustomizeAvatar : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gAgentWearables.areWearablesLoaded();
+ return new_value;
+ }
+};
+
+class LLEnableEditShape : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return gAgentWearables.isWearableModifiable(LLWearableType::WT_SHAPE, 0);
+ }
+};
+
+bool is_object_sittable()
+{
+ LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+
+ if (object && object->getPCode() == LL_PCODE_VOLUME)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+// only works on pie menu
+void handle_object_sit_or_stand()
+{
+ LLPickInfo pick = LLToolPie::getInstance()->getPick();
+ LLViewerObject *object = pick.getObject();;
+ if (!object || pick.mPickType == LLPickInfo::PICK_FLORA)
+ {
+ return;
+ }
+
+ if (sitting_on_selection())
+ {
+ gAgent.standUp();
+ return;
+ }
+
+ // get object selection offset
+
+ if (object && object->getPCode() == LL_PCODE_VOLUME)
+ {
+
+ gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit);
+ gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+ gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ gMessageSystem->nextBlockFast(_PREHASH_TargetObject);
+ gMessageSystem->addUUIDFast(_PREHASH_TargetID, object->mID);
+ gMessageSystem->addVector3Fast(_PREHASH_Offset, pick.mObjectOffset);
+
+ object->getRegion()->sendReliableMessage();
+ }
+}
+
+void near_sit_down_point(BOOL success, void *)
+{
+ if (success)
+ {
+ gAgent.setFlying(FALSE);
+ gAgent.setControlFlags(AGENT_CONTROL_SIT_ON_GROUND);
+
+ // Might be first sit
+ //LLFirstUse::useSit();
+ }
+}
+
+class LLLandSit : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gAgent.standUp();
+ LLViewerParcelMgr::getInstance()->deselectLand();
+
+ LLVector3d posGlobal = LLToolPie::getInstance()->getPick().mPosGlobal;
+
+ LLQuaternion target_rot;
+ if (isAgentAvatarValid())
+ {
+ target_rot = gAgentAvatarp->getRotation();
+ }
+ else
+ {
+ target_rot = gAgent.getFrameAgent().getQuaternion();
+ }
+ gAgent.startAutoPilotGlobal(posGlobal, "Sit", &target_rot, near_sit_down_point, NULL, 0.7f);
+ return true;
+ }
+};
+
+//-------------------------------------------------------------------
+// Help menu functions
+//-------------------------------------------------------------------
+
+//
+// Major mode switching
+//
+void reset_view_final( BOOL proceed );
+
+void handle_reset_view()
+{
+ if (gAgentCamera.cameraCustomizeAvatar())
+ {
+ // switching to outfit selector should automagically save any currently edited wearable
+ LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "my_outfits"));
+ }
+
+ gAgentCamera.switchCameraPreset(CAMERA_PRESET_REAR_VIEW);
+ reset_view_final( TRUE );
+ LLFloaterCamera::resetCameraMode();
+}
+
+class LLViewResetView : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_reset_view();
+ return true;
+ }
+};
+
+// Note: extra parameters allow this function to be called from dialog.
+void reset_view_final( BOOL proceed )
+{
+ if( !proceed )
+ {
+ return;
+ }
+
+ gAgentCamera.resetView(TRUE, TRUE);
+ gAgentCamera.setLookAt(LOOKAT_TARGET_CLEAR);
+}
+
+class LLViewLookAtLastChatter : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gAgentCamera.lookAtLastChat();
+ return true;
+ }
+};
+
+class LLViewMouselook : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if (!gAgentCamera.cameraMouselook())
+ {
+ gAgentCamera.changeCameraToMouselook();
+ }
+ else
+ {
+ gAgentCamera.changeCameraToDefault();
+ }
+ return true;
+ }
+};
+
+class LLViewDefaultUISize : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gSavedSettings.setF32("UIScaleFactor", 1.0f);
+ gSavedSettings.setBOOL("UIAutoScale", FALSE);
+ gViewerWindow->reshape(gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw());
+ return true;
+ }
+};
+
+class LLEditDuplicate : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if(LLEditMenuHandler::gEditMenuHandler)
+ {
+ LLEditMenuHandler::gEditMenuHandler->duplicate();
+ }
+ return true;
+ }
+};
+
+class LLEditEnableDuplicate : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDuplicate();
+ return new_value;
+ }
+};
+
+void handle_duplicate_in_place(void*)
+{
+ llinfos << "handle_duplicate_in_place" << llendl;
+
+ LLVector3 offset(0.f, 0.f, 0.f);
+ LLSelectMgr::getInstance()->selectDuplicate(offset, TRUE);
+}
+
+/* dead code 30-apr-2008
+void handle_deed_object_to_group(void*)
+{
+ LLUUID group_id;
+
+ LLSelectMgr::getInstance()->selectGetGroup(group_id);
+ LLSelectMgr::getInstance()->sendOwner(LLUUID::null, group_id, FALSE);
+ LLViewerStats::getInstance()->incStat(LLViewerStats::ST_RELEASE_COUNT);
+}
+
+BOOL enable_deed_object_to_group(void*)
+{
+ if(LLSelectMgr::getInstance()->getSelection()->isEmpty()) return FALSE;
+ LLPermissions perm;
+ LLUUID group_id;
+
+ if (LLSelectMgr::getInstance()->selectGetGroup(group_id) &&
+ gAgent.hasPowerInGroup(group_id, GP_OBJECT_DEED) &&
+ LLSelectMgr::getInstance()->selectGetPermissions(perm) &&
+ perm.deedToGroup(gAgent.getID(), group_id))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+*/
+
+
+/*
+ * No longer able to support viewer side manipulations in this way
+ *
+void god_force_inv_owner_permissive(LLViewerObject* object,
+ LLInventoryObject::object_list_t* inventory,
+ S32 serial_num,
+ void*)
+{
+ typedef std::vector<LLPointer<LLViewerInventoryItem> > item_array_t;
+ item_array_t items;
+
+ LLInventoryObject::object_list_t::const_iterator inv_it = inventory->begin();
+ LLInventoryObject::object_list_t::const_iterator inv_end = inventory->end();
+ for ( ; inv_it != inv_end; ++inv_it)
+ {
+ if(((*inv_it)->getType() != LLAssetType::AT_CATEGORY))
+ {
+ LLInventoryObject* obj = *inv_it;
+ LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem((LLViewerInventoryItem*)obj);
+ LLPermissions perm(new_item->getPermissions());
+ perm.setMaskBase(PERM_ALL);
+ perm.setMaskOwner(PERM_ALL);
+ new_item->setPermissions(perm);
+ items.push_back(new_item);
+ }
+ }
+ item_array_t::iterator end = items.end();
+ item_array_t::iterator it;
+ for(it = items.begin(); it != end; ++it)
+ {
+ // since we have the inventory item in the callback, it should not
+ // invalidate iteration through the selection manager.
+ object->updateInventory((*it), TASK_INVENTORY_ITEM_KEY, false);
+ }
+}
+*/
+
+void handle_object_owner_permissive(void*)
+{
+ // only send this if they're a god.
+ if(gAgent.isGodlike())
+ {
+ // do the objects.
+ LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_BASE, TRUE, PERM_ALL, TRUE);
+ LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, TRUE, PERM_ALL, TRUE);
+ }
+}
+
+void handle_object_owner_self(void*)
+{
+ // only send this if they're a god.
+ if(gAgent.isGodlike())
+ {
+ LLSelectMgr::getInstance()->sendOwner(gAgent.getID(), gAgent.getGroupID(), TRUE);
+ }
+}
+
+// Shortcut to set owner permissions to not editable.
+void handle_object_lock(void*)
+{
+ LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, FALSE, PERM_MODIFY);
+}
+
+void handle_object_asset_ids(void*)
+{
+ // only send this if they're a god.
+ if (gAgent.isGodlike())
+ {
+ LLSelectMgr::getInstance()->sendGodlikeRequest("objectinfo", "assetids");
+ }
+}
+
+void handle_force_parcel_owner_to_me(void*)
+{
+ LLViewerParcelMgr::getInstance()->sendParcelGodForceOwner( gAgent.getID() );
+}
+
+void handle_force_parcel_to_content(void*)
+{
+ LLViewerParcelMgr::getInstance()->sendParcelGodForceToContent();
+}
+
+void handle_claim_public_land(void*)
+{
+ if (LLViewerParcelMgr::getInstance()->getSelectionRegion() != gAgent.getRegion())
+ {
+ LLNotificationsUtil::add("ClaimPublicLand");
+ return;
+ }
+
+ LLVector3d west_south_global;
+ LLVector3d east_north_global;
+ LLViewerParcelMgr::getInstance()->getSelection(west_south_global, east_north_global);
+ LLVector3 west_south = gAgent.getPosAgentFromGlobal(west_south_global);
+ LLVector3 east_north = gAgent.getPosAgentFromGlobal(east_north_global);
+
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessage("GodlikeMessage");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID", gAgent.getID());
+ msg->addUUID("SessionID", gAgent.getSessionID());
+ msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used
+ msg->nextBlock("MethodData");
+ msg->addString("Method", "claimpublicland");
+ msg->addUUID("Invoice", LLUUID::null);
+ std::string buffer;
+ buffer = llformat( "%f", west_south.mV[VX]);
+ msg->nextBlock("ParamList");
+ msg->addString("Parameter", buffer);
+ buffer = llformat( "%f", west_south.mV[VY]);
+ msg->nextBlock("ParamList");
+ msg->addString("Parameter", buffer);
+ buffer = llformat( "%f", east_north.mV[VX]);
+ msg->nextBlock("ParamList");
+ msg->addString("Parameter", buffer);
+ buffer = llformat( "%f", east_north.mV[VY]);
+ msg->nextBlock("ParamList");
+ msg->addString("Parameter", buffer);
+ gAgent.sendReliableMessage();
+}
+
+
+
+// HACK for easily testing new avatar geometry
+void handle_god_request_avatar_geometry(void *)
+{
+ if (gAgent.isGodlike())
+ {
+ LLSelectMgr::getInstance()->sendGodlikeRequest("avatar toggle", "");
+ }
+}
+
+
+void derez_objects(EDeRezDestination dest, const LLUUID& dest_id)
+{
+ if(gAgentCamera.cameraMouselook())
+ {
+ gAgentCamera.changeCameraToDefault();
+ }
+ //gInventoryView->setPanelOpen(TRUE);
+
+ std::string error;
+ LLDynamicArray<LLViewerObject*> derez_objects;
+
+ // Check conditions that we can't deal with, building a list of
+ // everything that we'll actually be derezzing.
+ LLViewerRegion* first_region = NULL;
+ for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin();
+ iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++)
+ {
+ LLSelectNode* node = *iter;
+ LLViewerObject* object = node->getObject();
+ LLViewerRegion* region = object->getRegion();
+ if (!first_region)
+ {
+ first_region = region;
+ }
+ else
+ {
+ if(region != first_region)
+ {
+ // Derez doesn't work at all if the some of the objects
+ // are in regions besides the first object selected.
+
+ // ...crosses region boundaries
+ error = "AcquireErrorObjectSpan";
+ break;
+ }
+ }
+ if (object->isAvatar())
+ {
+ // ...don't acquire avatars
+ continue;
+ }
+
+ // If AssetContainers are being sent back, they will appear as
+ // boxes in the owner's inventory.
+ if (object->getNVPair("AssetContainer")
+ && dest != DRD_RETURN_TO_OWNER)
+ {
+ // this object is an asset container, derez its contents, not it
+ llwarns << "Attempt to derez deprecated AssetContainer object type not supported." << llendl;
+ /*
+ object->requestInventory(container_inventory_arrived,
+ (void *)(BOOL)(DRD_TAKE_INTO_AGENT_INVENTORY == dest));
+ */
+ continue;
+ }
+ BOOL can_derez_current = FALSE;
+ switch(dest)
+ {
+ case DRD_TAKE_INTO_AGENT_INVENTORY:
+ case DRD_TRASH:
+ if( (node->mPermissions->allowTransferTo(gAgent.getID()) && object->permModify())
+ || (node->allowOperationOnNode(PERM_OWNER, GP_OBJECT_MANIPULATE)) )
+ {
+ can_derez_current = TRUE;
+ }
+ break;
+
+ case DRD_RETURN_TO_OWNER:
+ can_derez_current = TRUE;
+ break;
+
+ default:
+ if((node->mPermissions->allowTransferTo(gAgent.getID())
+ && object->permCopy())
+ || gAgent.isGodlike())
+ {
+ can_derez_current = TRUE;
+ }
+ break;
+ }
+ if(can_derez_current)
+ {
+ derez_objects.put(object);
+ }
+ }
+
+ // This constant is based on (1200 - HEADER_SIZE) / 4 bytes per
+ // root. I lopped off a few (33) to provide a bit
+ // pad. HEADER_SIZE is currently 67 bytes, most of which is UUIDs.
+ // This gives us a maximum of 63500 root objects - which should
+ // satisfy anybody.
+ const S32 MAX_ROOTS_PER_PACKET = 250;
+ const S32 MAX_PACKET_COUNT = 254;
+ F32 packets = ceil((F32)derez_objects.count() / (F32)MAX_ROOTS_PER_PACKET);
+ if(packets > (F32)MAX_PACKET_COUNT)
+ {
+ error = "AcquireErrorTooManyObjects";
+ }
+
+ if(error.empty() && derez_objects.count() > 0)
+ {
+ U8 d = (U8)dest;
+ LLUUID tid;
+ tid.generate();
+ U8 packet_count = (U8)packets;
+ S32 object_index = 0;
+ S32 objects_in_packet = 0;
+ LLMessageSystem* msg = gMessageSystem;
+ for(U8 packet_number = 0;
+ packet_number < packet_count;
+ ++packet_number)
+ {
+ msg->newMessageFast(_PREHASH_DeRezObject);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_AgentBlock);
+ msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID());
+ msg->addU8Fast(_PREHASH_Destination, d);
+ msg->addUUIDFast(_PREHASH_DestinationID, dest_id);
+ msg->addUUIDFast(_PREHASH_TransactionID, tid);
+ msg->addU8Fast(_PREHASH_PacketCount, packet_count);
+ msg->addU8Fast(_PREHASH_PacketNumber, packet_number);
+ objects_in_packet = 0;
+ while((object_index < derez_objects.count())
+ && (objects_in_packet++ < MAX_ROOTS_PER_PACKET))
+
+ {
+ LLViewerObject* object = derez_objects.get(object_index++);
+ msg->nextBlockFast(_PREHASH_ObjectData);
+ msg->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID());
+ // VEFFECT: DerezObject
+ LLHUDEffectSpiral* effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
+ effectp->setPositionGlobal(object->getPositionGlobal());
+ effectp->setColor(LLColor4U(gAgent.getEffectColor()));
+ }
+ msg->sendReliable(first_region->getHost());
+ }
+ make_ui_sound("UISndObjectRezOut");
+
+ // Busy count decremented by inventory update, so only increment
+ // if will be causing an update.
+ if (dest != DRD_RETURN_TO_OWNER)
+ {
+ gViewerWindow->getWindow()->incBusyCount();
+ }
+ }
+ else if(!error.empty())
+ {
+ LLNotificationsUtil::add(error);
+ }
+}
+
+void handle_take_copy()
+{
+ if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return;
+
+ const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT);
+ derez_objects(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id);
+}
+
+// You can return an object to its owner if it is on your land.
+class LLObjectReturn : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true;
+
+ mObjectSelection = LLSelectMgr::getInstance()->getEditSelection();
+
+ LLNotificationsUtil::add("ReturnToOwner", LLSD(), LLSD(), boost::bind(&LLObjectReturn::onReturnToOwner, this, _1, _2));
+ return true;
+ }
+
+ bool onReturnToOwner(const LLSD& notification, const LLSD& response)
+ {
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (0 == option)
+ {
+ // Ignore category ID for this derez destination.
+ derez_objects(DRD_RETURN_TO_OWNER, LLUUID::null);
+ }
+
+ // drop reference to current selection
+ mObjectSelection = NULL;
+ return false;
+ }
+
+protected:
+ LLObjectSelectionHandle mObjectSelection;
+};
+
+
+// Allow return to owner if one or more of the selected items is
+// over land you own.
+class LLObjectEnableReturn : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if (LLSelectMgr::getInstance()->getSelection()->isEmpty())
+ {
+ // Do not enable if nothing selected
+ return false;
+ }
+#ifdef HACKED_GODLIKE_VIEWER
+ bool new_value = true;
+#else
+ bool new_value = false;
+ if (gAgent.isGodlike())
+ {
+ new_value = true;
+ }
+ else
+ {
+ LLViewerRegion* region = gAgent.getRegion();
+ if (region)
+ {
+ // Estate owners and managers can always return objects.
+ if (region->canManageEstate())
+ {
+ new_value = true;
+ }
+ else
+ {
+ struct f : public LLSelectedObjectFunctor
+ {
+ virtual bool apply(LLViewerObject* obj)
+ {
+ return
+ obj->permModify() ||
+ obj->isReturnable();
+ }
+ } func;
+ const bool firstonly = true;
+ new_value = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly);
+ }
+ }
+ }
+#endif
+ return new_value;
+ }
+};
+
+void force_take_copy(void*)
+{
+ if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return;
+ const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT);
+ derez_objects(DRD_FORCE_TO_GOD_INVENTORY, category_id);
+}
+
+void handle_take()
+{
+ // we want to use the folder this was derezzed from if it's
+ // available. Otherwise, derez to the normal place.
+ if(LLSelectMgr::getInstance()->getSelection()->isEmpty())
+ {
+ return;
+ }
+
+ BOOL you_own_everything = TRUE;
+ BOOL locked_but_takeable_object = FALSE;
+ LLUUID category_id;
+
+ for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin();
+ iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++)
+ {
+ LLSelectNode* node = *iter;
+ LLViewerObject* object = node->getObject();
+ if(object)
+ {
+ if(!object->permYouOwner())
+ {
+ you_own_everything = FALSE;
+ }
+
+ if(!object->permMove())
+ {
+ locked_but_takeable_object = TRUE;
+ }
+ }
+ if(node->mFolderID.notNull())
+ {
+ if(category_id.isNull())
+ {
+ category_id = node->mFolderID;
+ }
+ else if(category_id != node->mFolderID)
+ {
+ // we have found two potential destinations. break out
+ // now and send to the default location.
+ category_id.setNull();
+ break;
+ }
+ }
+ }
+ if(category_id.notNull())
+ {
+ // there is an unambiguous destination. See if this agent has
+ // such a location and it is not in the trash or library
+ if(!gInventory.getCategory(category_id))
+ {
+ // nope, set to NULL.
+ category_id.setNull();
+ }
+ if(category_id.notNull())
+ {
+ // check trash
+ const LLUUID trash = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ if(category_id == trash || gInventory.isObjectDescendentOf(category_id, trash))
+ {
+ category_id.setNull();
+ }
+
+ // check library
+ if(gInventory.isObjectDescendentOf(category_id, gInventory.getLibraryRootFolderID()))
+ {
+ category_id.setNull();
+ }
+
+ }
+ }
+ if(category_id.isNull())
+ {
+ category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT);
+ }
+ LLSD payload;
+ payload["folder_id"] = category_id;
+
+ LLNotification::Params params("ConfirmObjectTakeLock");
+ params.payload(payload);
+ params.functor.function(confirm_take);
+
+ if(locked_but_takeable_object ||
+ !you_own_everything)
+ {
+ if(locked_but_takeable_object && you_own_everything)
+ {
+ params.name("ConfirmObjectTakeLock");
+ }
+ else if(!locked_but_takeable_object && !you_own_everything)
+ {
+ params.name("ConfirmObjectTakeNoOwn");
+ }
+ else
+ {
+ params.name("ConfirmObjectTakeLockNoOwn");
+ }
+
+ LLNotifications::instance().add(params);
+ }
+ else
+ {
+ LLNotifications::instance().forceResponse(params, 0);
+ }
+}
+
+void handle_object_show_inspector()
+{
+ LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+ LLViewerObject* objectp = selection->getFirstRootObject(TRUE);
+ if (!objectp)
+ {
+ return;
+ }
+
+ LLSD params;
+ params["object_id"] = objectp->getID();
+ LLFloaterReg::showInstance("inspect_object", params);
+}
+
+void handle_avatar_show_inspector()
+{
+ LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
+ if(avatar)
+ {
+ LLSD params;
+ params["avatar_id"] = avatar->getID();
+ LLFloaterReg::showInstance("inspect_avatar", params);
+ }
+}
+
+
+
+bool confirm_take(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if(enable_take() && (option == 0))
+ {
+ derez_objects(DRD_TAKE_INTO_AGENT_INVENTORY, notification["payload"]["folder_id"].asUUID());
+ }
+ return false;
+}
+
+// You can take an item when it is public and transferrable, or when
+// you own it. We err on the side of enabling the item when at least
+// one item selected can be copied to inventory.
+BOOL enable_take()
+{
+ if (sitting_on_selection())
+ {
+ return FALSE;
+ }
+
+ for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin();
+ iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++)
+ {
+ LLSelectNode* node = *iter;
+ LLViewerObject* object = node->getObject();
+ if (object->isAvatar())
+ {
+ // ...don't acquire avatars
+ continue;
+ }
+
+#ifdef HACKED_GODLIKE_VIEWER
+ return TRUE;
+#else
+# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
+ if (!LLGridManager::getInstance()->isInProductionGrid()
+ && gAgent.isGodlike())
+ {
+ return TRUE;
+ }
+# endif
+ if((node->mPermissions->allowTransferTo(gAgent.getID())
+ && object->permModify())
+ || (node->mPermissions->getOwner() == gAgent.getID()))
+ {
+ return TRUE;
+ }
+#endif
+ }
+ return FALSE;
+}
+
+
+void handle_buy_or_take()
+{
+ if (LLSelectMgr::getInstance()->getSelection()->isEmpty())
+ {
+ return;
+ }
+
+ if (is_selection_buy_not_take())
+ {
+ S32 total_price = selection_price();
+
+ if (total_price <= gStatusBar->getBalance() || total_price == 0)
+ {
+ handle_buy();
+ }
+ else
+ {
+ LLStringUtil::format_map_t args;
+ args["AMOUNT"] = llformat("%d", total_price);
+ LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString( "BuyingCosts", args ), total_price );
+ }
+ }
+ else
+ {
+ handle_take();
+ }
+}
+
+bool visible_buy_object()
+{
+ return is_selection_buy_not_take() && enable_buy_object();
+}
+
+bool visible_take_object()
+{
+ return !is_selection_buy_not_take() && enable_take();
+}
+
+bool tools_visible_buy_object()
+{
+ return is_selection_buy_not_take();
+}
+
+bool tools_visible_take_object()
+{
+ return !is_selection_buy_not_take();
+}
+
+class LLToolsEnableBuyOrTake : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool is_buy = is_selection_buy_not_take();
+ bool new_value = is_buy ? enable_buy_object() : enable_take();
+ return new_value;
+ }
+};
+
+// This is a small helper function to determine if we have a buy or a
+// take in the selection. This method is to help with the aliasing
+// problems of putting buy and take in the same pie menu space. After
+// a fair amont of discussion, it was determined to prefer buy over
+// take. The reasoning follows from the fact that when users walk up
+// to buy something, they will click on one or more items. Thus, if
+// anything is for sale, it becomes a buy operation, and the server
+// will group all of the buy items, and copyable/modifiable items into
+// one package and give the end user as much as the permissions will
+// allow. If the user wanted to take something, they will select fewer
+// and fewer items until only 'takeable' items are left. The one
+// exception is if you own everything in the selection that is for
+// sale, in this case, you can't buy stuff from yourself, so you can
+// take it.
+// return value = TRUE if selection is a 'buy'.
+// FALSE if selection is a 'take'
+BOOL is_selection_buy_not_take()
+{
+ for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin();
+ iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++)
+ {
+ LLSelectNode* node = *iter;
+ LLViewerObject* obj = node->getObject();
+ if(obj && !(obj->permYouOwner()) && (node->mSaleInfo.isForSale()))
+ {
+ // you do not own the object and it is for sale, thus,
+ // it's a buy
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+S32 selection_price()
+{
+ S32 total_price = 0;
+ for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin();
+ iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++)
+ {
+ LLSelectNode* node = *iter;
+ LLViewerObject* obj = node->getObject();
+ if(obj && !(obj->permYouOwner()) && (node->mSaleInfo.isForSale()))
+ {
+ // you do not own the object and it is for sale.
+ // Add its price.
+ total_price += node->mSaleInfo.getSalePrice();
+ }
+ }
+
+ return total_price;
+}
+/*
+bool callback_show_buy_currency(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (0 == option)
+ {
+ llinfos << "Loading page " << LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL") << llendl;
+ LLWeb::loadURL(LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL"));
+ }
+ return false;
+}
+*/
+
+void show_buy_currency(const char* extra)
+{
+ // Don't show currency web page for branded clients.
+/*
+ std::ostringstream mesg;
+ if (extra != NULL)
+ {
+ mesg << extra << "\n \n";
+ }
+ mesg << "Go to " << LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL")<< "\nfor information on purchasing currency?";
+*/
+ LLSD args;
+ if (extra != NULL)
+ {
+ args["EXTRA"] = extra;
+ }
+ LLNotificationsUtil::add("PromptGoToCurrencyPage", args);//, LLSD(), callback_show_buy_currency);
+}
+
+void handle_buy()
+{
+ if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return;
+
+ LLSaleInfo sale_info;
+ BOOL valid = LLSelectMgr::getInstance()->selectGetSaleInfo(sale_info);
+ if (!valid) return;
+
+ S32 price = sale_info.getSalePrice();
+
+ if (price > 0 && price > gStatusBar->getBalance())
+ {
+ LLStringUtil::format_map_t args;
+ args["AMOUNT"] = llformat("%d", price);
+ LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("this_object_costs", args), price );
+ return;
+ }
+
+ if (sale_info.getSaleType() == LLSaleInfo::FS_CONTENTS)
+ {
+ handle_buy_contents(sale_info);
+ }
+ else
+ {
+ handle_buy_object(sale_info);
+ }
+}
+
+bool anyone_copy_selection(LLSelectNode* nodep)
+{
+ bool perm_copy = (bool)(nodep->getObject()->permCopy());
+ bool all_copy = (bool)(nodep->mPermissions->getMaskEveryone() & PERM_COPY);
+ return perm_copy && all_copy;
+}
+
+bool for_sale_selection(LLSelectNode* nodep)
+{
+ return nodep->mSaleInfo.isForSale()
+ && nodep->mPermissions->getMaskOwner() & PERM_TRANSFER
+ && (nodep->mPermissions->getMaskOwner() & PERM_COPY
+ || nodep->mSaleInfo.getSaleType() != LLSaleInfo::FS_COPY);
+}
+
+BOOL sitting_on_selection()
+{
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
+ if (!node)
+ {
+ return FALSE;
+ }
+
+ if (!node->mValid)
+ {
+ return FALSE;
+ }
+
+ LLViewerObject* root_object = node->getObject();
+ if (!root_object)
+ {
+ return FALSE;
+ }
+
+ // Need to determine if avatar is sitting on this object
+ if (!isAgentAvatarValid()) return FALSE;
+
+ return (gAgentAvatarp->isSitting() && gAgentAvatarp->getRoot() == root_object);
+}
+
+class LLToolsSaveToInventory : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if(enable_save_into_inventory(NULL))
+ {
+ derez_objects(DRD_SAVE_INTO_AGENT_INVENTORY, LLUUID::null);
+ }
+ return true;
+ }
+};
+
+class LLToolsSaveToObjectInventory : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
+ if(node && (node->mValid) && (!node->mFromTaskID.isNull()))
+ {
+ // *TODO: check to see if the fromtaskid object exists.
+ derez_objects(DRD_SAVE_INTO_TASK_INVENTORY, node->mFromTaskID);
+ }
+ return true;
+ }
+};
+
+// Round the position of all root objects to the grid
+class LLToolsSnapObjectXY : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ F64 snap_size = (F64)gSavedSettings.getF32("GridResolution");
+
+ for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin();
+ iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++)
+ {
+ LLSelectNode* node = *iter;
+ LLViewerObject* obj = node->getObject();
+ if (obj->permModify())
+ {
+ LLVector3d pos_global = obj->getPositionGlobal();
+ F64 round_x = fmod(pos_global.mdV[VX], snap_size);
+ if (round_x < snap_size * 0.5)
+ {
+ // closer to round down
+ pos_global.mdV[VX] -= round_x;
+ }
+ else
+ {
+ // closer to round up
+ pos_global.mdV[VX] -= round_x;
+ pos_global.mdV[VX] += snap_size;
+ }
+
+ F64 round_y = fmod(pos_global.mdV[VY], snap_size);
+ if (round_y < snap_size * 0.5)
+ {
+ pos_global.mdV[VY] -= round_y;
+ }
+ else
+ {
+ pos_global.mdV[VY] -= round_y;
+ pos_global.mdV[VY] += snap_size;
+ }
+
+ obj->setPositionGlobal(pos_global, FALSE);
+ }
+ }
+ LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_POSITION);
+ return true;
+ }
+};
+
+// Determine if the option to cycle between linked prims is shown
+class LLToolsEnableSelectNextPart : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = (gSavedSettings.getBOOL("EditLinkedParts") &&
+ !LLSelectMgr::getInstance()->getSelection()->isEmpty());
+ return new_value;
+ }
+};
+
+// Cycle selection through linked children in selected object.
+// FIXME: Order of children list is not always the same as sim's idea of link order. This may confuse
+// resis. Need link position added to sim messages to address this.
+class LLToolsSelectNextPart : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ S32 object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+ if (gSavedSettings.getBOOL("EditLinkedParts") && object_count)
+ {
+ LLViewerObject* selected = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
+ if (selected && selected->getRootEdit())
+ {
+ bool fwd = (userdata.asString() == "next");
+ bool prev = (userdata.asString() == "previous");
+ bool ifwd = (userdata.asString() == "includenext");
+ bool iprev = (userdata.asString() == "includeprevious");
+ LLViewerObject* to_select = NULL;
+ LLViewerObject::child_list_t children = selected->getRootEdit()->getChildren();
+ children.push_front(selected->getRootEdit()); // need root in the list too
+
+ for (LLViewerObject::child_list_t::iterator iter = children.begin(); iter != children.end(); ++iter)
+ {
+ if ((*iter)->isSelected())
+ {
+ if (object_count > 1 && (fwd || prev)) // multiple selection, find first or last selected if not include
+ {
+ to_select = *iter;
+ if (fwd)
+ {
+ // stop searching if going forward; repeat to get last hit if backward
+ break;
+ }
+ }
+ else if ((object_count == 1) || (ifwd || iprev)) // single selection or include
+ {
+ if (fwd || ifwd)
+ {
+ ++iter;
+ while (iter != children.end() && ((*iter)->isAvatar() || (ifwd && (*iter)->isSelected())))
+ {
+ ++iter; // skip sitting avatars and selected if include
+ }
+ }
+ else // backward
+ {
+ iter = (iter == children.begin() ? children.end() : iter);
+ --iter;
+ while (iter != children.begin() && ((*iter)->isAvatar() || (iprev && (*iter)->isSelected())))
+ {
+ --iter; // skip sitting avatars and selected if include
+ }
+ }
+ iter = (iter == children.end() ? children.begin() : iter);
+ to_select = *iter;
+ break;
+ }
+ }
+ }
+
+ if (to_select)
+ {
+ if (gFocusMgr.childHasKeyboardFocus(gFloaterTools))
+ {
+ gFocusMgr.setKeyboardFocus(NULL); // force edit toolbox to commit any changes
+ }
+ if (fwd || prev)
+ {
+ LLSelectMgr::getInstance()->deselectAll();
+ }
+ LLSelectMgr::getInstance()->selectObjectOnly(to_select);
+ return true;
+ }
+ }
+ }
+ return true;
+ }
+};
+
+class LLToolsStopAllAnimations : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gAgent.stopCurrentAnimations();
+ return true;
+ }
+};
+
+class LLToolsReleaseKeys : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gAgent.forceReleaseControls();
+
+ return true;
+ }
+};
+
+class LLToolsEnableReleaseKeys : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return gAgent.anyControlGrabbed();
+ }
+};
+
+
+class LLEditEnableCut : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCut();
+ return new_value;
+ }
+};
+
+class LLEditCut : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if( LLEditMenuHandler::gEditMenuHandler )
+ {
+ LLEditMenuHandler::gEditMenuHandler->cut();
+ }
+ return true;
+ }
+};
+
+class LLEditEnableCopy : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCopy();
+ return new_value;
+ }
+};
+
+class LLEditCopy : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if( LLEditMenuHandler::gEditMenuHandler )
+ {
+ LLEditMenuHandler::gEditMenuHandler->copy();
+ }
+ return true;
+ }
+};
+
+class LLEditEnablePaste : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canPaste();
+ return new_value;
+ }
+};
+
+class LLEditPaste : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if( LLEditMenuHandler::gEditMenuHandler )
+ {
+ LLEditMenuHandler::gEditMenuHandler->paste();
+ }
+ return true;
+ }
+};
+
+class LLEditEnableDelete : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDoDelete();
+ return new_value;
+ }
+};
+
+class LLEditDelete : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ // If a text field can do a deletion, it gets precedence over deleting
+ // an object in the world.
+ if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDoDelete())
+ {
+ LLEditMenuHandler::gEditMenuHandler->doDelete();
+ }
+
+ // and close any pie/context menus when done
+ gMenuHolder->hideMenus();
+
+ // When deleting an object we may not actually be done
+ // Keep selection so we know what to delete when confirmation is needed about the delete
+ gMenuObject->hide();
+ return true;
+ }
+};
+
+bool enable_object_delete()
+{
+ bool new_value =
+#ifdef HACKED_GODLIKE_VIEWER
+ TRUE;
+#else
+# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
+ (!LLGridManager::getInstance()->isInProductionGrid()
+ && gAgent.isGodlike()) ||
+# endif
+ LLSelectMgr::getInstance()->canDoDelete();
+#endif
+ return new_value;
+}
+
+void handle_object_delete()
+{
+
+ if (LLSelectMgr::getInstance())
+ {
+ LLSelectMgr::getInstance()->doDelete();
+ }
+
+ // and close any pie/context menus when done
+ gMenuHolder->hideMenus();
+
+ // When deleting an object we may not actually be done
+ // Keep selection so we know what to delete when confirmation is needed about the delete
+ gMenuObject->hide();
+ return;
+}
+
+void handle_force_delete(void*)
+{
+ LLSelectMgr::getInstance()->selectForceDelete();
+}
+
+class LLViewEnableJoystickFlycam : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = (gSavedSettings.getBOOL("JoystickEnabled") && gSavedSettings.getBOOL("JoystickFlycamEnabled"));
+ return new_value;
+ }
+};
+
+class LLViewEnableLastChatter : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ // *TODO: add check that last chatter is in range
+ bool new_value = (gAgentCamera.cameraThirdPerson() && gAgent.getLastChatter().notNull());
+ return new_value;
+ }
+};
+
+class LLEditEnableDeselect : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDeselect();
+ return new_value;
+ }
+};
+
+class LLEditDeselect : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if( LLEditMenuHandler::gEditMenuHandler )
+ {
+ LLEditMenuHandler::gEditMenuHandler->deselect();
+ }
+ return true;
+ }
+};
+
+class LLEditEnableSelectAll : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canSelectAll();
+ return new_value;
+ }
+};
+
+
+class LLEditSelectAll : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if( LLEditMenuHandler::gEditMenuHandler )
+ {
+ LLEditMenuHandler::gEditMenuHandler->selectAll();
+ }
+ return true;
+ }
+};
+
+
+class LLEditEnableUndo : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo();
+ return new_value;
+ }
+};
+
+class LLEditUndo : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo() )
+ {
+ LLEditMenuHandler::gEditMenuHandler->undo();
+ }
+ return true;
+ }
+};
+
+class LLEditEnableRedo : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo();
+ return new_value;
+ }
+};
+
+class LLEditRedo : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo() )
+ {
+ LLEditMenuHandler::gEditMenuHandler->redo();
+ }
+ return true;
+ }
+};
+
+
+
+void print_object_info(void*)
+{
+ LLSelectMgr::getInstance()->selectionDump();
+}
+
+void print_agent_nvpairs(void*)
+{
+ LLViewerObject *objectp;
+
+ llinfos << "Agent Name Value Pairs" << llendl;
+
+ objectp = gObjectList.findObject(gAgentID);
+ if (objectp)
+ {
+ objectp->printNameValuePairs();
+ }
+ else
+ {
+ llinfos << "Can't find agent object" << llendl;
+ }
+
+ llinfos << "Camera at " << gAgentCamera.getCameraPositionGlobal() << llendl;
+}
+
+void show_debug_menus()
+{
+ // this might get called at login screen where there is no menu so only toggle it if one exists
+ if ( gMenuBarView )
+ {
+ BOOL debug = gSavedSettings.getBOOL("UseDebugMenus");
+ BOOL qamode = gSavedSettings.getBOOL("QAMode");
+
+ gMenuBarView->setItemVisible("Advanced", debug);
+// gMenuBarView->setItemEnabled("Advanced", debug); // Don't disable Advanced keyboard shortcuts when hidden
+
+ gMenuBarView->setItemVisible("Debug", qamode);
+ gMenuBarView->setItemEnabled("Debug", qamode);
+
+ gMenuBarView->setItemVisible("Develop", qamode);
+ gMenuBarView->setItemEnabled("Develop", qamode);
+
+ // Server ('Admin') menu hidden when not in godmode.
+ const bool show_server_menu = (gAgent.getGodLevel() > GOD_NOT || (debug && gAgent.getAdminOverride()));
+ gMenuBarView->setItemVisible("Admin", show_server_menu);
+ gMenuBarView->setItemEnabled("Admin", show_server_menu);
+ }
+ if (gLoginMenuBarView)
+ {
+ BOOL debug = gSavedSettings.getBOOL("UseDebugMenus");
+ gLoginMenuBarView->setItemVisible("Debug", debug);
+ gLoginMenuBarView->setItemEnabled("Debug", debug);
+ }
+}
+
+void toggle_debug_menus(void*)
+{
+ BOOL visible = ! gSavedSettings.getBOOL("UseDebugMenus");
+ gSavedSettings.setBOOL("UseDebugMenus", visible);
+ show_debug_menus();
+}
+
+
+// LLUUID gExporterRequestID;
+// std::string gExportDirectory;
+
+// LLUploadDialog *gExportDialog = NULL;
+
+// void handle_export_selected( void * )
+// {
+// LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+// if (selection->isEmpty())
+// {
+// return;
+// }
+// llinfos << "Exporting selected objects:" << llendl;
+
+// gExporterRequestID.generate();
+// gExportDirectory = "";
+
+// LLMessageSystem* msg = gMessageSystem;
+// msg->newMessageFast(_PREHASH_ObjectExportSelected);
+// msg->nextBlockFast(_PREHASH_AgentData);
+// msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+// msg->addUUIDFast(_PREHASH_RequestID, gExporterRequestID);
+// msg->addS16Fast(_PREHASH_VolumeDetail, 4);
+
+// for (LLObjectSelection::root_iterator iter = selection->root_begin();
+// iter != selection->root_end(); iter++)
+// {
+// LLSelectNode* node = *iter;
+// LLViewerObject* object = node->getObject();
+// msg->nextBlockFast(_PREHASH_ObjectData);
+// msg->addUUIDFast(_PREHASH_ObjectID, object->getID());
+// llinfos << "Object: " << object->getID() << llendl;
+// }
+// msg->sendReliable(gAgent.getRegion()->getHost());
+
+// gExportDialog = LLUploadDialog::modalUploadDialog("Exporting selected objects...");
+// }
+//
+
+
+class LLWorldSetHomeLocation : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ // we just send the message and let the server check for failure cases
+ // server will echo back a "Home position set." alert if it succeeds
+ // and the home location screencapture happens when that alert is recieved
+ gAgent.setStartPosition(START_LOCATION_ID_HOME);
+ return true;
+ }
+};
+
+class LLWorldTeleportHome : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gAgent.teleportHome();
+ return true;
+ }
+};
+
+class LLWorldAlwaysRun : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ // as well as altering the default walk-vs-run state,
+ // we also change the *current* walk-vs-run state.
+ if (gAgent.getAlwaysRun())
+ {
+ gAgent.clearAlwaysRun();
+ gAgent.clearRunning();
+ }
+ else
+ {
+ gAgent.setAlwaysRun();
+ gAgent.setRunning();
+ }
+
+ // tell the simulator.
+ gAgent.sendWalkRun(gAgent.getAlwaysRun());
+
+ // Update Movement Controls according to AlwaysRun mode
+ LLFloaterMove::setAlwaysRunMode(gAgent.getAlwaysRun());
+
+ return true;
+ }
+};
+
+class LLWorldCheckAlwaysRun : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gAgent.getAlwaysRun();
+ return new_value;
+ }
+};
+
+class LLWorldSetAway : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if (gAgent.getAFK())
+ {
+ gAgent.clearAFK();
+ }
+ else
+ {
+ gAgent.setAFK();
+ }
+ return true;
+ }
+};
+
+class LLWorldSetBusy : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if (gAgent.getBusy())
+ {
+ gAgent.clearBusy();
+ }
+ else
+ {
+ gAgent.setBusy();
+ LLNotificationsUtil::add("BusyModeSet");
+ }
+ return true;
+ }
+};
+
+class LLWorldCreateLandmark : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLSideTray::getInstance()->showPanel("panel_places", LLSD().with("type", "create_landmark"));
+
+ return true;
+ }
+};
+
+class LLWorldPlaceProfile : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLSideTray::getInstance()->showPanel("panel_places", LLSD().with("type", "agent"));
+
+ return true;
+ }
+};
+
+void handle_look_at_selection(const LLSD& param)
+{
+ const F32 PADDING_FACTOR = 1.75f;
+ BOOL zoom = (param.asString() == "zoom");
+ if (!LLSelectMgr::getInstance()->getSelection()->isEmpty())
+ {
+ gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);
+
+ LLBBox selection_bbox = LLSelectMgr::getInstance()->getBBoxOfSelection();
+ F32 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getAspect() > 1.f ? LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect() : LLViewerCamera::getInstance()->getView());
+ F32 distance = selection_bbox.getExtentLocal().magVec() * PADDING_FACTOR / atan(angle_of_view);
+
+ LLVector3 obj_to_cam = LLViewerCamera::getInstance()->getOrigin() - selection_bbox.getCenterAgent();
+ obj_to_cam.normVec();
+
+ LLUUID object_id;
+ if (LLSelectMgr::getInstance()->getSelection()->getPrimaryObject())
+ {
+ object_id = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()->mID;
+ }
+ if (zoom)
+ {
+ // Make sure we are not increasing the distance between the camera and object
+ LLVector3d orig_distance = gAgentCamera.getCameraPositionGlobal() - LLSelectMgr::getInstance()->getSelectionCenterGlobal();
+ distance = llmin(distance, (F32) orig_distance.length());
+
+ gAgentCamera.setCameraPosAndFocusGlobal(LLSelectMgr::getInstance()->getSelectionCenterGlobal() + LLVector3d(obj_to_cam * distance),
+ LLSelectMgr::getInstance()->getSelectionCenterGlobal(),
+ object_id );
+
+ }
+ else
+ {
+ gAgentCamera.setFocusGlobal( LLSelectMgr::getInstance()->getSelectionCenterGlobal(), object_id );
+ }
+ }
+}
+
+void handle_zoom_to_object(LLUUID object_id)
+{
+ const F32 PADDING_FACTOR = 2.f;
+
+ LLViewerObject* object = gObjectList.findObject(object_id);
+
+ if (object)
+ {
+ gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);
+
+ LLBBox bbox = object->getBoundingBoxAgent() ;
+ F32 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getAspect() > 1.f ? LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect() : LLViewerCamera::getInstance()->getView());
+ F32 distance = bbox.getExtentLocal().magVec() * PADDING_FACTOR / atan(angle_of_view);
+
+ LLVector3 obj_to_cam = LLViewerCamera::getInstance()->getOrigin() - bbox.getCenterAgent();
+ obj_to_cam.normVec();
+
+
+ LLVector3d object_center_global = gAgent.getPosGlobalFromAgent(bbox.getCenterAgent());
+
+ gAgentCamera.setCameraPosAndFocusGlobal(object_center_global + LLVector3d(obj_to_cam * distance),
+ object_center_global,
+ object_id );
+ }
+}
+
+class LLAvatarInviteToGroup : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
+ if(avatar)
+ {
+ LLAvatarActions::inviteToGroup(avatar->getID());
+ }
+ return true;
+ }
+};
+
+class LLAvatarAddFriend : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
+ if(avatar && !LLAvatarActions::isFriend(avatar->getID()))
+ {
+ request_friendship(avatar->getID());
+ }
+ return true;
+ }
+};
+
+class LLAvatarAddContact : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
+ if(avatar)
+ {
+ create_inventory_callingcard(avatar->getID());
+ }
+ return true;
+ }
+};
+
+bool complete_give_money(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle selection)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option == 0)
+ {
+ gAgent.clearBusy();
+ }
+
+ LLViewerObject* objectp = selection->getPrimaryObject();
+
+ // Show avatar's name if paying attachment
+ if (objectp && objectp->isAttachment())
+ {
+ while (objectp && !objectp->isAvatar())
+ {
+ objectp = (LLViewerObject*)objectp->getParent();
+ }
+ }
+
+ if (objectp)
+ {
+ if (objectp->isAvatar())
+ {
+ const bool is_group = false;
+ LLFloaterPayUtil::payDirectly(&give_money,
+ objectp->getID(),
+ is_group);
+ }
+ else
+ {
+ LLFloaterPayUtil::payViaObject(&give_money, selection);
+ }
+ }
+ return false;
+}
+
+void handle_give_money_dialog()
+{
+ LLNotification::Params params("BusyModePay");
+ params.functor.function(boost::bind(complete_give_money, _1, _2, LLSelectMgr::getInstance()->getSelection()));
+
+ if (gAgent.getBusy())
+ {
+ // warn users of being in busy mode during a transaction
+ LLNotifications::instance().add(params);
+ }
+ else
+ {
+ LLNotifications::instance().forceResponse(params, 1);
+ }
+}
+
+bool enable_pay_avatar()
+{
+ LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ LLVOAvatar* avatar = find_avatar_from_object(obj);
+ return (avatar != NULL);
+}
+
+bool enable_pay_object()
+{
+ LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ if( object )
+ {
+ LLViewerObject *parent = (LLViewerObject *)object->getParent();
+ if((object->flagTakesMoney()) || (parent && parent->flagTakesMoney()))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool enable_object_stand_up()
+{
+ // 'Object Stand Up' menu item is enabled when agent is sitting on selection
+ return sitting_on_selection();
+}
+
+bool enable_object_sit(LLUICtrl* ctrl)
+{
+ // 'Object Sit' menu item is enabled when agent is not sitting on selection
+ bool sitting_on_sel = sitting_on_selection();
+ if (!sitting_on_sel)
+ {
+ std::string item_name = ctrl->getName();
+
+ // init default labels
+ init_default_item_label(item_name);
+
+ // Update label
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
+ if (node && node->mValid && !node->mSitName.empty())
+ {
+ gMenuHolder->childSetText(item_name, node->mSitName);
+ }
+ else
+ {
+ gMenuHolder->childSetText(item_name, get_default_item_label(item_name));
+ }
+ }
+ return !sitting_on_sel && is_object_sittable();
+}
+
+void dump_select_mgr(void*)
+{
+ LLSelectMgr::getInstance()->dump();
+}
+
+void dump_inventory(void*)
+{
+ gInventory.dumpInventory();
+}
+
+
+void handle_dump_followcam(void*)
+{
+ LLFollowCamMgr::dump();
+}
+
+void handle_viewer_enable_message_log(void*)
+{
+ gMessageSystem->startLogging();
+}
+
+void handle_viewer_disable_message_log(void*)
+{
+ gMessageSystem->stopLogging();
+}
+
+void handle_customize_avatar()
+{
+ LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "my_outfits"));
+}
+
+void handle_edit_outfit()
+{
+ LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_outfit"));
+}
+
+void handle_edit_shape()
+{
+ LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_shape"));
+}
+
+void handle_report_abuse()
+{
+ // Prevent menu from appearing in screen shot.
+ gMenuHolder->hideMenus();
+ LLFloaterReporter::showFromMenu(COMPLAINT_REPORT);
+}
+
+void handle_buy_currency()
+{
+ LLBuyCurrencyHTML::openCurrencyFloater();
+}
+
+class LLFloaterVisible : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string floater_name = userdata.asString();
+ bool new_value = false;
+ {
+ new_value = LLFloaterReg::instanceVisible(floater_name);
+ }
+ return new_value;
+ }
+};
+
+class LLShowHelp : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string help_topic = userdata.asString();
+ LLViewerHelp* vhelp = LLViewerHelp::getInstance();
+ vhelp->showTopic(help_topic);
+ return true;
+ }
+};
+
+class LLToggleHelp : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLFloater* help_browser = (LLFloaterReg::findInstance("help_browser"));
+ if (help_browser && help_browser->isInVisibleChain())
+ {
+ help_browser->closeFloater();
+ }
+ else
+ {
+ std::string help_topic = userdata.asString();
+ LLViewerHelp* vhelp = LLViewerHelp::getInstance();
+ vhelp->showTopic(help_topic);
+ }
+ return true;
+ }
+};
+
+class LLShowSidetrayPanel : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string panel_name = userdata.asString();
+
+ LLPanel* panel = LLSideTray::getInstance()->getPanel(panel_name);
+ if (panel)
+ {
+ if (panel->isInVisibleChain())
+ {
+ LLSideTray::getInstance()->hidePanel(panel_name);
+ }
+ else
+ {
+ LLSideTray::getInstance()->showPanel(panel_name);
+ }
+ }
+ return true;
+ }
+};
+
+class LLSidetrayPanelVisible : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string panel_name = userdata.asString();
+ // Toggle the panel
+ if (LLSideTray::getInstance()->isPanelActive(panel_name))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+
+ }
+};
+
+
+bool callback_show_url(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (0 == option)
+ {
+ LLWeb::loadURL(notification["payload"]["url"].asString());
+ }
+ return false;
+}
+
+class LLPromptShowURL : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string param = userdata.asString();
+ std::string::size_type offset = param.find(",");
+ if (offset != param.npos)
+ {
+ std::string alert = param.substr(0, offset);
+ std::string url = param.substr(offset+1);
+
+ if(gSavedSettings.getBOOL("UseExternalBrowser"))
+ {
+ LLSD payload;
+ payload["url"] = url;
+ LLNotificationsUtil::add(alert, LLSD(), payload, callback_show_url);
+ }
+ else
+ {
+ LLWeb::loadURL(url);
+ }
+ }
+ else
+ {
+ llinfos << "PromptShowURL invalid parameters! Expecting \"ALERT,URL\"." << llendl;
+ }
+ return true;
+ }
+};
+
+bool callback_show_file(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (0 == option)
+ {
+ LLWeb::loadURL(notification["payload"]["url"]);
+ }
+ return false;
+}
+
+class LLPromptShowFile : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string param = userdata.asString();
+ std::string::size_type offset = param.find(",");
+ if (offset != param.npos)
+ {
+ std::string alert = param.substr(0, offset);
+ std::string file = param.substr(offset+1);
+
+ LLSD payload;
+ payload["url"] = file;
+ LLNotificationsUtil::add(alert, LLSD(), payload, callback_show_file);
+ }
+ else
+ {
+ llinfos << "PromptShowFile invalid parameters! Expecting \"ALERT,FILE\"." << llendl;
+ }
+ return true;
+ }
+};
+
+class LLShowAgentProfile : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLUUID agent_id;
+ if (userdata.asString() == "agent")
+ {
+ agent_id = gAgent.getID();
+ }
+ else if (userdata.asString() == "hit object")
+ {
+ LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ if (objectp)
+ {
+ agent_id = objectp->getID();
+ }
+ }
+ else
+ {
+ agent_id = userdata.asUUID();
+ }
+
+ LLVOAvatar* avatar = find_avatar_from_object(agent_id);
+ if (avatar)
+ {
+ LLAvatarActions::showProfile(avatar->getID());
+ }
+ return true;
+ }
+};
+
+class LLToggleAgentProfile : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLUUID agent_id;
+ if (userdata.asString() == "agent")
+ {
+ agent_id = gAgent.getID();
+ }
+ else if (userdata.asString() == "hit object")
+ {
+ LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ if (objectp)
+ {
+ agent_id = objectp->getID();
+ }
+ }
+ else
+ {
+ agent_id = userdata.asUUID();
+ }
+
+ LLVOAvatar* avatar = find_avatar_from_object(agent_id);
+ if (avatar)
+ {
+ if (!LLAvatarActions::profileVisible(avatar->getID()))
+ {
+ LLAvatarActions::showProfile(avatar->getID());
+ }
+ else
+ {
+ LLAvatarActions::hideProfile(avatar->getID());
+ }
+ }
+ return true;
+ }
+};
+
+class LLLandEdit : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if (gAgentCamera.getFocusOnAvatar() && gSavedSettings.getBOOL("EditCameraMovement") )
+ {
+ // zoom in if we're looking at the avatar
+ gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);
+ gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick());
+
+ gAgentCamera.cameraOrbitOver( F_PI * 0.25f );
+ gViewerWindow->moveCursorToCenter();
+ }
+ else if ( gSavedSettings.getBOOL("EditCameraMovement") )
+ {
+ gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick());
+ gViewerWindow->moveCursorToCenter();
+ }
+
+
+ LLViewerParcelMgr::getInstance()->selectParcelAt( LLToolPie::getInstance()->getPick().mPosGlobal );
+
+ LLFloaterReg::showInstance("build");
+
+ // Switch to land edit toolset
+ LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolSelectLand::getInstance() );
+ return true;
+ }
+};
+
+class LLWorldEnableBuyLand : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLViewerParcelMgr::getInstance()->canAgentBuyParcel(
+ LLViewerParcelMgr::getInstance()->selectionEmpty()
+ ? LLViewerParcelMgr::getInstance()->getAgentParcel()
+ : LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(),
+ false);
+ return new_value;
+ }
+};
+
+BOOL enable_buy_land(void*)
+{
+ return LLViewerParcelMgr::getInstance()->canAgentBuyParcel(
+ LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(), false);
+}
+
+void handle_buy_land()
+{
+ LLViewerParcelMgr* vpm = LLViewerParcelMgr::getInstance();
+ if (vpm->selectionEmpty())
+ {
+ vpm->selectParcelAt(gAgent.getPositionGlobal());
+ }
+ vpm->startBuyLand();
+}
+
+class LLObjectAttachToAvatar : public view_listener_t
+{
+public:
+ LLObjectAttachToAvatar(bool replace) : mReplace(replace) {}
+ static void setObjectSelection(LLObjectSelectionHandle selection) { sObjectSelection = selection; }
+
+private:
+ bool handleEvent(const LLSD& userdata)
+ {
+ setObjectSelection(LLSelectMgr::getInstance()->getSelection());
+ LLViewerObject* selectedObject = sObjectSelection->getFirstRootObject();
+ if (selectedObject)
+ {
+ S32 index = userdata.asInteger();
+ LLViewerJointAttachment* attachment_point = NULL;
+ if (index > 0)
+ attachment_point = get_if_there(gAgentAvatarp->mAttachmentPoints, index, (LLViewerJointAttachment*)NULL);
+ confirmReplaceAttachment(0, attachment_point);
+ }
+ return true;
+ }
+
+ static void onNearAttachObject(BOOL success, void *user_data);
+ void confirmReplaceAttachment(S32 option, LLViewerJointAttachment* attachment_point);
+
+ struct CallbackData
+ {
+ CallbackData(LLViewerJointAttachment* point, bool replace) : mAttachmentPoint(point), mReplace(replace) {}
+
+ LLViewerJointAttachment* mAttachmentPoint;
+ bool mReplace;
+ };
+
+protected:
+ static LLObjectSelectionHandle sObjectSelection;
+ bool mReplace;
+};
+
+LLObjectSelectionHandle LLObjectAttachToAvatar::sObjectSelection;
+
+// static
+void LLObjectAttachToAvatar::onNearAttachObject(BOOL success, void *user_data)
+{
+ if (!user_data) return;
+ CallbackData* cb_data = static_cast<CallbackData*>(user_data);
+
+ if (success)
+ {
+ const LLViewerJointAttachment *attachment = cb_data->mAttachmentPoint;
+
+ U8 attachment_id = 0;
+ if (attachment)
+ {
+ for (LLVOAvatar::attachment_map_t::const_iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
+ iter != gAgentAvatarp->mAttachmentPoints.end(); ++iter)
+ {
+ if (iter->second == attachment)
+ {
+ attachment_id = iter->first;
+ break;
+ }
+ }
+ }
+ else
+ {
+ // interpret 0 as "default location"
+ attachment_id = 0;
+ }
+ LLSelectMgr::getInstance()->sendAttach(attachment_id, cb_data->mReplace);
+ }
+ LLObjectAttachToAvatar::setObjectSelection(NULL);
+
+ delete cb_data;
+}
+
+// static
+void LLObjectAttachToAvatar::confirmReplaceAttachment(S32 option, LLViewerJointAttachment* attachment_point)
+{
+ if (option == 0/*YES*/)
+ {
+ LLViewerObject* selectedObject = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject();
+ if (selectedObject)
+ {
+ const F32 MIN_STOP_DISTANCE = 1.f; // meters
+ const F32 ARM_LENGTH = 0.5f; // meters
+ const F32 SCALE_FUDGE = 1.5f;
+
+ F32 stop_distance = SCALE_FUDGE * selectedObject->getMaxScale() + ARM_LENGTH;
+ if (stop_distance < MIN_STOP_DISTANCE)
+ {
+ stop_distance = MIN_STOP_DISTANCE;
+ }
+
+ LLVector3 walkToSpot = selectedObject->getPositionAgent();
+
+ // make sure we stop in front of the object
+ LLVector3 delta = walkToSpot - gAgent.getPositionAgent();
+ delta.normVec();
+ delta = delta * 0.5f;
+ walkToSpot -= delta;
+
+ // The callback will be called even if avatar fails to get close enough to the object, so we won't get a memory leak.
+ CallbackData* user_data = new CallbackData(attachment_point, mReplace);
+ gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(walkToSpot), "Attach", NULL, onNearAttachObject, user_data, stop_distance);
+ gAgentCamera.clearFocusObject();
+ }
+ }
+}
+
+void callback_attachment_drop(const LLSD& notification, const LLSD& response)
+{
+ // Ensure user confirmed the drop
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option != 0) return;
+
+ // Called when the user clicked on an object attached to them
+ // and selected "Drop".
+ LLUUID object_id = notification["payload"]["object_id"].asUUID();
+ LLViewerObject *object = gObjectList.findObject(object_id);
+
+ if (!object)
+ {
+ llwarns << "handle_drop_attachment() - no object to drop" << llendl;
+ return;
+ }
+
+ LLViewerObject *parent = (LLViewerObject*)object->getParent();
+ while (parent)
+ {
+ if(parent->isAvatar())
+ {
+ break;
+ }
+ object = parent;
+ parent = (LLViewerObject*)parent->getParent();
+ }
+
+ if (!object)
+ {
+ llwarns << "handle_detach() - no object to detach" << llendl;
+ return;
+ }
+
+ if (object->isAvatar())
+ {
+ llwarns << "Trying to detach avatar from avatar." << llendl;
+ return;
+ }
+
+ // reselect the object
+ LLSelectMgr::getInstance()->selectObjectAndFamily(object);
+
+ LLSelectMgr::getInstance()->sendDropAttachment();
+
+ return;
+}
+
+class LLAttachmentDrop : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLSD payload;
+ LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+
+ if (object)
+ {
+ payload["object_id"] = object->getID();
+ }
+ else
+ {
+ llwarns << "Drop object not found" << llendl;
+ return true;
+ }
+
+ LLNotificationsUtil::add("AttachmentDrop", LLSD(), payload, &callback_attachment_drop);
+ return true;
+ }
+};
+
+// called from avatar pie menu
+class LLAttachmentDetachFromPoint : public view_listener_t
+{
+ bool handleEvent(const LLSD& user_data)
+ {
+ const LLViewerJointAttachment *attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, user_data.asInteger(), (LLViewerJointAttachment*)NULL);
+ if (attachment->getNumObjects() > 0)
+ {
+ gMessageSystem->newMessage("ObjectDetach");
+ gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+ gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
+ gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+
+ for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator iter = attachment->mAttachedObjects.begin();
+ iter != attachment->mAttachedObjects.end();
+ iter++)
+ {
+ LLViewerObject *attached_object = (*iter);
+ gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
+ gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, attached_object->getLocalID());
+ }
+ gMessageSystem->sendReliable( gAgent.getRegionHost() );
+ }
+ return true;
+ }
+};
+
+static bool onEnableAttachmentLabel(LLUICtrl* ctrl, const LLSD& data)
+{
+ std::string label;
+ LLMenuItemGL* menu = dynamic_cast<LLMenuItemGL*>(ctrl);
+ if (menu)
+ {
+ const LLViewerJointAttachment *attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, data["index"].asInteger(), (LLViewerJointAttachment*)NULL);
+ if (attachment)
+ {
+ label = data["label"].asString();
+ for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator attachment_iter = attachment->mAttachedObjects.begin();
+ attachment_iter != attachment->mAttachedObjects.end();
+ ++attachment_iter)
+ {
+ const LLViewerObject* attached_object = (*attachment_iter);
+ if (attached_object)
+ {
+ LLViewerInventoryItem* itemp = gInventory.getItem(attached_object->getAttachmentItemID());
+ if (itemp)
+ {
+ label += std::string(" (") + itemp->getName() + std::string(")");
+ break;
+ }
+ }
+ }
+ }
+ menu->setLabel(label);
+ }
+ return true;
+}
+
+class LLAttachmentDetach : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ // Called when the user clicked on an object attached to them
+ // and selected "Detach".
+ LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ if (!object)
+ {
+ llwarns << "handle_detach() - no object to detach" << llendl;
+ return true;
+ }
+
+ LLViewerObject *parent = (LLViewerObject*)object->getParent();
+ while (parent)
+ {
+ if(parent->isAvatar())
+ {
+ break;
+ }
+ object = parent;
+ parent = (LLViewerObject*)parent->getParent();
+ }
+
+ if (!object)
+ {
+ llwarns << "handle_detach() - no object to detach" << llendl;
+ return true;
+ }
+
+ if (object->isAvatar())
+ {
+ llwarns << "Trying to detach avatar from avatar." << llendl;
+ return true;
+ }
+
+ // The sendDetach() method works on the list of selected
+ // objects. Thus we need to clear the list, make sure it only
+ // contains the object the user clicked, send the message,
+ // then clear the list.
+ // We use deselectAll to update the simulator's notion of what's
+ // selected, and removeAll just to change things locally.
+ //RN: I thought it was more useful to detach everything that was selected
+ if (LLSelectMgr::getInstance()->getSelection()->isAttachment())
+ {
+ LLSelectMgr::getInstance()->sendDetach();
+ }
+ return true;
+ }
+};
+
+//Adding an observer for a Jira 2422 and needs to be a fetch observer
+//for Jira 3119
+class LLWornItemFetchedObserver : public LLInventoryFetchItemsObserver
+{
+public:
+ LLWornItemFetchedObserver(const LLUUID& worn_item_id) :
+ LLInventoryFetchItemsObserver(worn_item_id)
+ {}
+ virtual ~LLWornItemFetchedObserver() {}
+
+protected:
+ virtual void done()
+ {
+ gMenuAttachmentSelf->buildDrawLabels();
+ gInventory.removeObserver(this);
+ delete this;
+ }
+};
+
+// You can only drop items on parcels where you can build.
+class LLAttachmentEnableDrop : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ BOOL can_build = gAgent.isGodlike() || (LLViewerParcelMgr::getInstance()->allowAgentBuild());
+
+ //Add an inventory observer to only allow dropping the newly attached item
+ //once it exists in your inventory. Look at Jira 2422.
+ //-jwolk
+
+ // A bug occurs when you wear/drop an item before it actively is added to your inventory
+ // if this is the case (you're on a slow sim, etc.) a copy of the object,
+ // well, a newly created object with the same properties, is placed
+ // in your inventory. Therefore, we disable the drop option until the
+ // item is in your inventory
+
+ LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ LLViewerJointAttachment* attachment = NULL;
+ LLInventoryItem* item = NULL;
+
+ // Do not enable drop if all faces of object are not enabled
+ if (object && LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES ))
+ {
+ S32 attachmentID = ATTACHMENT_ID_FROM_STATE(object->getState());
+ attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL);
+
+ if (attachment)
+ {
+ for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+ attachment_iter != attachment->mAttachedObjects.end();
+ ++attachment_iter)
+ {
+ // make sure item is in your inventory (it could be a delayed attach message being sent from the sim)
+ // so check to see if the item is in the inventory already
+ item = gInventory.getItem((*attachment_iter)->getAttachmentItemID());
+ if (!item)
+ {
+ // Item does not exist, make an observer to enable the pie menu
+ // when the item finishes fetching worst case scenario
+ // if a fetch is already out there (being sent from a slow sim)
+ // we refetch and there are 2 fetches
+ LLWornItemFetchedObserver* worn_item_fetched = new LLWornItemFetchedObserver((*attachment_iter)->getAttachmentItemID());
+ worn_item_fetched->startFetch();
+ gInventory.addObserver(worn_item_fetched);
+ }
+ }
+ }
+ }
+
+ //now check to make sure that the item is actually in the inventory before we enable dropping it
+ bool new_value = enable_detach() && can_build && item;
+
+ return new_value;
+ }
+};
+
+BOOL enable_detach(const LLSD&)
+{
+ LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+
+ // Only enable detach if all faces of object are selected
+ if (!object ||
+ !object->isAttachment() ||
+ !LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES ))
+ {
+ return FALSE;
+ }
+
+ // Find the avatar who owns this attachment
+ LLViewerObject* avatar = object;
+ while (avatar)
+ {
+ // ...if it's you, good to detach
+ if (avatar->getID() == gAgent.getID())
+ {
+ return TRUE;
+ }
+
+ avatar = (LLViewerObject*)avatar->getParent();
+ }
+
+ return FALSE;
+}
+
+class LLAttachmentEnableDetach : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = enable_detach();
+ return new_value;
+ }
+};
+
+// Used to tell if the selected object can be attached to your avatar.
+BOOL object_selected_and_point_valid()
+{
+ LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+ for (LLObjectSelection::root_iterator iter = selection->root_begin();
+ iter != selection->root_end(); iter++)
+ {
+ LLSelectNode* node = *iter;
+ LLViewerObject* object = node->getObject();
+ LLViewerObject::const_child_list_t& child_list = object->getChildren();
+ for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
+ iter != child_list.end(); iter++)
+ {
+ LLViewerObject* child = *iter;
+ if (child->isAvatar())
+ {
+ return FALSE;
+ }
+ }
+ }
+
+ return (selection->getRootObjectCount() == 1) &&
+ (selection->getFirstRootObject()->getPCode() == LL_PCODE_VOLUME) &&
+ selection->getFirstRootObject()->permYouOwner() &&
+ selection->getFirstRootObject()->flagObjectMove() &&
+ !((LLViewerObject*)selection->getFirstRootObject()->getRoot())->isAvatar() &&
+ (selection->getFirstRootObject()->getNVPair("AssetContainer") == NULL);
+}
+
+
+BOOL object_is_wearable()
+{
+ if (!object_selected_and_point_valid())
+ {
+ return FALSE;
+ }
+ if (sitting_on_selection())
+ {
+ return FALSE;
+ }
+ LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+ for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin();
+ iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++)
+ {
+ LLSelectNode* node = *iter;
+ if (node->mPermissions->getOwner() == gAgent.getID())
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+class LLAttachmentPointFilled : public view_listener_t
+{
+ bool handleEvent(const LLSD& user_data)
+ {
+ bool enable = false;
+ LLVOAvatar::attachment_map_t::iterator found_it = gAgentAvatarp->mAttachmentPoints.find(user_data.asInteger());
+ if (found_it != gAgentAvatarp->mAttachmentPoints.end())
+ {
+ enable = found_it->second->getNumObjects() > 0;
+ }
+ return enable;
+ }
+};
+
+class LLAvatarSendIM : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
+ if(avatar)
+ {
+ LLAvatarActions::startIM(avatar->getID());
+ }
+ return true;
+ }
+};
+
+class LLAvatarCall : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
+ if(avatar)
+ {
+ LLAvatarActions::startCall(avatar->getID());
+ }
+ return true;
+ }
+};
+
+namespace
+{
+ struct QueueObjects : public LLSelectedObjectFunctor
+ {
+ BOOL scripted;
+ BOOL modifiable;
+ LLFloaterScriptQueue* mQueue;
+ QueueObjects(LLFloaterScriptQueue* q) : mQueue(q), scripted(FALSE), modifiable(FALSE) {}
+ virtual bool apply(LLViewerObject* obj)
+ {
+ scripted = obj->flagScripted();
+ modifiable = obj->permModify();
+
+ if( scripted && modifiable )
+ {
+ mQueue->addObject(obj->getID());
+ return false;
+ }
+ else
+ {
+ return true; // fail: stop applying
+ }
+ }
+ };
+}
+
+void queue_actions(LLFloaterScriptQueue* q, const std::string& msg)
+{
+ QueueObjects func(q);
+ LLSelectMgr *mgr = LLSelectMgr::getInstance();
+ LLObjectSelectionHandle selectHandle = mgr->getSelection();
+ bool fail = selectHandle->applyToObjects(&func);
+ if(fail)
+ {
+ if ( !func.scripted )
+ {
+ std::string noscriptmsg = std::string("Cannot") + msg + "SelectObjectsNoScripts";
+ LLNotificationsUtil::add(noscriptmsg);
+ }
+ else if ( !func.modifiable )
+ {
+ std::string nomodmsg = std::string("Cannot") + msg + "SelectObjectsNoPermission";
+ LLNotificationsUtil::add(nomodmsg);
+ }
+ else
+ {
+ llerrs << "Bad logic." << llendl;
+ }
+ }
+ else
+ {
+ if (!q->start())
+ {
+ llwarns << "Unexpected script compile failure." << llendl;
+ }
+ }
+}
+
+class LLToolsSelectedScriptAction : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string action = userdata.asString();
+ bool mono = false;
+ std::string msg, name;
+ if (action == "compile mono")
+ {
+ name = "compile_queue";
+ mono = true;
+ msg = "Recompile";
+ }
+ if (action == "compile lsl")
+ {
+ name = "compile_queue";
+ msg = "Recompile";
+ }
+ else if (action == "reset")
+ {
+ name = "reset_queue";
+ msg = "Reset";
+ }
+ else if (action == "start")
+ {
+ name = "start_queue";
+ msg = "Running";
+ }
+ else if (action == "stop")
+ {
+ name = "stop_queue";
+ msg = "RunningNot";
+ }
+ LLUUID id; id.generate();
+
+ LLFloaterScriptQueue* queue =LLFloaterReg::getTypedInstance<LLFloaterScriptQueue>(name, LLSD(id));
+ if (queue)
+ {
+ queue->setMono(mono);
+ queue_actions(queue, msg);
+ }
+ else
+ {
+ llwarns << "Failed to generate LLFloaterScriptQueue with action: " << action << llendl;
+ }
+ return true;
+ }
+};
+
+void handle_selected_texture_info(void*)
+{
+ for (LLObjectSelection::valid_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_begin();
+ iter != LLSelectMgr::getInstance()->getSelection()->valid_end(); iter++)
+ {
+ LLSelectNode* node = *iter;
+
+ std::string msg;
+ msg.assign("Texture info for: ");
+ msg.append(node->mName);
+
+ LLSD args;
+ args["MESSAGE"] = msg;
+ LLNotificationsUtil::add("SystemMessage", args);
+
+ U8 te_count = node->getObject()->getNumTEs();
+ // map from texture ID to list of faces using it
+ typedef std::map< LLUUID, std::vector<U8> > map_t;
+ map_t faces_per_texture;
+ for (U8 i = 0; i < te_count; i++)
+ {
+ if (!node->isTESelected(i)) continue;
+
+ LLViewerTexture* img = node->getObject()->getTEImage(i);
+ LLUUID image_id = img->getID();
+ faces_per_texture[image_id].push_back(i);
+ }
+ // Per-texture, dump which faces are using it.
+ map_t::iterator it;
+ for (it = faces_per_texture.begin(); it != faces_per_texture.end(); ++it)
+ {
+ LLUUID image_id = it->first;
+ U8 te = it->second[0];
+ LLViewerTexture* img = node->getObject()->getTEImage(te);
+ S32 height = img->getHeight();
+ S32 width = img->getWidth();
+ S32 components = img->getComponents();
+ msg = llformat("%dx%d %s on face ",
+ width,
+ height,
+ (components == 4 ? "alpha" : "opaque"));
+ for (U8 i = 0; i < it->second.size(); ++i)
+ {
+ msg.append( llformat("%d ", (S32)(it->second[i])));
+ }
+
+ LLSD args;
+ args["MESSAGE"] = msg;
+ LLNotificationsUtil::add("SystemMessage", args);
+ }
+ }
+}
+
+void handle_test_male(void*)
+{
+ LLAppearanceMgr::instance().wearOutfitByName("Male Shape & Outfit");
+ //gGestureList.requestResetFromServer( TRUE );
+}
+
+void handle_test_female(void*)
+{
+ LLAppearanceMgr::instance().wearOutfitByName("Female Shape & Outfit");
+ //gGestureList.requestResetFromServer( FALSE );
+}
+
+void handle_toggle_pg(void*)
+{
+ gAgent.setTeen( !gAgent.isTeen() );
+
+ LLFloaterWorldMap::reloadIcons(NULL);
+
+ llinfos << "PG status set to " << (S32)gAgent.isTeen() << llendl;
+}
+
+void handle_dump_attachments(void*)
+{
+ if(!isAgentAvatarValid()) return;
+
+ for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
+ iter != gAgentAvatarp->mAttachmentPoints.end(); )
+ {
+ LLVOAvatar::attachment_map_t::iterator curiter = iter++;
+ LLViewerJointAttachment* attachment = curiter->second;
+ S32 key = curiter->first;
+ for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+ attachment_iter != attachment->mAttachedObjects.end();
+ ++attachment_iter)
+ {
+ LLViewerObject *attached_object = (*attachment_iter);
+ BOOL visible = (attached_object != NULL &&
+ attached_object->mDrawable.notNull() &&
+ !attached_object->mDrawable->isRenderType(0));
+ LLVector3 pos;
+ if (visible) pos = attached_object->mDrawable->getPosition();
+ llinfos << "ATTACHMENT " << key << ": item_id=" << attached_object->getAttachmentItemID()
+ << (attached_object ? " present " : " absent ")
+ << (visible ? "visible " : "invisible ")
+ << " at " << pos
+ << " and " << (visible ? attached_object->getPosition() : LLVector3::zero)
+ << llendl;
+ }
+ }
+}
+
+
+// these are used in the gl menus to set control values, generically.
+class LLToggleControl : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string control_name = userdata.asString();
+ BOOL checked = gSavedSettings.getBOOL( control_name );
+ gSavedSettings.setBOOL( control_name, !checked );
+ return true;
+ }
+};
+
+class LLCheckControl : public view_listener_t
+{
+ bool handleEvent( const LLSD& userdata)
+ {
+ std::string callback_data = userdata.asString();
+ bool new_value = gSavedSettings.getBOOL(callback_data);
+ return new_value;
+ }
+};
+
+// not so generic
+
+class LLAdvancedCheckRenderShadowOption: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string control_name = userdata.asString();
+ S32 current_shadow_level = gSavedSettings.getS32(control_name);
+ if (current_shadow_level == 0) // is off
+ {
+ return false;
+ }
+ else // is on
+ {
+ return true;
+ }
+ }
+};
+
+class LLAdvancedClickRenderShadowOption: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string control_name = userdata.asString();
+ S32 current_shadow_level = gSavedSettings.getS32(control_name);
+ if (current_shadow_level == 0) // upgrade to level 2
+ {
+ gSavedSettings.setS32(control_name, 2);
+ }
+ else // downgrade to level 0
+ {
+ gSavedSettings.setS32(control_name, 0);
+ }
+ return true;
+ }
+};
+
+void menu_toggle_attached_lights(void* user_data)
+{
+ LLPipeline::sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights");
+}
+
+void menu_toggle_attached_particles(void* user_data)
+{
+ LLPipeline::sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles");
+}
+
+class LLAdvancedHandleAttachedLightParticles: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string control_name = userdata.asString();
+
+ // toggle the control
+ gSavedSettings.setBOOL(control_name,
+ !gSavedSettings.getBOOL(control_name));
+
+ // update internal flags
+ if (control_name == "RenderAttachedLights")
+ {
+ menu_toggle_attached_lights(NULL);
+ }
+ else if (control_name == "RenderAttachedParticles")
+ {
+ menu_toggle_attached_particles(NULL);
+ }
+ return true;
+ }
+};
+
+class LLSomethingSelected : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = !(LLSelectMgr::getInstance()->getSelection()->isEmpty());
+ return new_value;
+ }
+};
+
+class LLSomethingSelectedNoHUD : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+ bool new_value = !(selection->isEmpty()) && !(selection->getSelectType() == SELECT_TYPE_HUD);
+ return new_value;
+ }
+};
+
+static bool is_editable_selected()
+{
+ return (LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject() != NULL);
+}
+
+class LLEditableSelected : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return is_editable_selected();
+ }
+};
+
+class LLEditableSelectedMono : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = false;
+ LLViewerRegion* region = gAgent.getRegion();
+ if(region && gMenuHolder)
+ {
+ bool have_cap = (! region->getCapability("UpdateScriptTask").empty());
+ new_value = is_editable_selected() && have_cap;
+ }
+ return new_value;
+ }
+};
+
+bool enable_object_take_copy()
+{
+ bool all_valid = false;
+ if (LLSelectMgr::getInstance())
+ {
+ if (!LLSelectMgr::getInstance()->getSelection()->isEmpty())
+ {
+ all_valid = true;
+#ifndef HACKED_GODLIKE_VIEWER
+# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
+ if (LLGridManager::getInstance()->isInProductionGrid()
+ || !gAgent.isGodlike())
+# endif
+ {
+ struct f : public LLSelectedObjectFunctor
+ {
+ virtual bool apply(LLViewerObject* obj)
+ {
+ return (!obj->permCopy() || obj->isAttachment());
+ }
+ } func;
+ const bool firstonly = true;
+ bool any_invalid = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly);
+ all_valid = !any_invalid;
+ }
+#endif // HACKED_GODLIKE_VIEWER
+ }
+ }
+
+ return all_valid;
+}
+
+
+class LLHasAsset : public LLInventoryCollectFunctor
+{
+public:
+ LLHasAsset(const LLUUID& id) : mAssetID(id), mHasAsset(FALSE) {}
+ virtual ~LLHasAsset() {}
+ virtual bool operator()(LLInventoryCategory* cat,
+ LLInventoryItem* item);
+ BOOL hasAsset() const { return mHasAsset; }
+
+protected:
+ LLUUID mAssetID;
+ BOOL mHasAsset;
+};
+
+bool LLHasAsset::operator()(LLInventoryCategory* cat,
+ LLInventoryItem* item)
+{
+ if(item && item->getAssetUUID() == mAssetID)
+ {
+ mHasAsset = TRUE;
+ }
+ return FALSE;
+}
+
+BOOL enable_save_into_inventory(void*)
+{
+ // *TODO: clean this up
+ // find the last root
+ LLSelectNode* last_node = NULL;
+ for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin();
+ iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++)
+ {
+ last_node = *iter;
+ }
+
+#ifdef HACKED_GODLIKE_VIEWER
+ return TRUE;
+#else
+# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
+ if (!LLGridManager::getInstance()->isInProductionGrid()
+ && gAgent.isGodlike())
+ {
+ return TRUE;
+ }
+# endif
+ // check all pre-req's for save into inventory.
+ if(last_node && last_node->mValid && !last_node->mItemID.isNull()
+ && (last_node->mPermissions->getOwner() == gAgent.getID())
+ && (gInventory.getItem(last_node->mItemID) != NULL))
+ {
+ LLViewerObject* obj = last_node->getObject();
+ if( obj && !obj->isAttachment() )
+ {
+ return TRUE;
+ }
+ }
+#endif
+ return FALSE;
+}
+
+class LLToolsEnableSaveToInventory : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = enable_save_into_inventory(NULL);
+ return new_value;
+ }
+};
+
+BOOL enable_save_into_task_inventory(void*)
+{
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
+ if(node && (node->mValid) && (!node->mFromTaskID.isNull()))
+ {
+ // *TODO: check to see if the fromtaskid object exists.
+ LLViewerObject* obj = node->getObject();
+ if( obj && !obj->isAttachment() )
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+class LLToolsEnableSaveToObjectInventory : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = enable_save_into_task_inventory(NULL);
+ return new_value;
+ }
+};
+
+
+class LLViewEnableMouselook : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ // You can't go directly from customize avatar to mouselook.
+ // TODO: write code with appropriate dialogs to handle this transition.
+ bool new_value = (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && !gSavedSettings.getBOOL("FreezeTime"));
+ return new_value;
+ }
+};
+
+class LLToolsEnableToolNotPie : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = ( LLToolMgr::getInstance()->getBaseTool() != LLToolPie::getInstance() );
+ return new_value;
+ }
+};
+
+class LLWorldEnableCreateLandmark : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return !LLLandmarkActions::landmarkAlreadyExists();
+ }
+};
+
+class LLWorldEnableSetHomeLocation : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gAgent.isGodlike() ||
+ (gAgent.getRegion() && gAgent.getRegion()->getAllowSetHome());
+ return new_value;
+ }
+};
+
+class LLWorldEnableTeleportHome : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLViewerRegion* regionp = gAgent.getRegion();
+ bool agent_on_prelude = (regionp && regionp->isPrelude());
+ bool enable_teleport_home = gAgent.isGodlike() || !agent_on_prelude;
+ return enable_teleport_home;
+ }
+};
+
+BOOL enable_god_full(void*)
+{
+ return gAgent.getGodLevel() >= GOD_FULL;
+}
+
+BOOL enable_god_liaison(void*)
+{
+ return gAgent.getGodLevel() >= GOD_LIAISON;
+}
+
+bool is_god_customer_service()
+{
+ return gAgent.getGodLevel() >= GOD_CUSTOMER_SERVICE;
+}
+
+BOOL enable_god_basic(void*)
+{
+ return gAgent.getGodLevel() > GOD_NOT;
+}
+
+
+void toggle_show_xui_names(void *)
+{
+ gSavedSettings.setBOOL("DebugShowXUINames", !gSavedSettings.getBOOL("DebugShowXUINames"));
+}
+
+BOOL check_show_xui_names(void *)
+{
+ return gSavedSettings.getBOOL("DebugShowXUINames");
+}
+
+class LLToolsSelectOnlyMyObjects : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ BOOL cur_val = gSavedSettings.getBOOL("SelectOwnedOnly");
+
+ gSavedSettings.setBOOL("SelectOwnedOnly", ! cur_val );
+
+ return true;
+ }
+};
+
+class LLToolsSelectOnlyMovableObjects : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ BOOL cur_val = gSavedSettings.getBOOL("SelectMovableOnly");
+
+ gSavedSettings.setBOOL("SelectMovableOnly", ! cur_val );
+
+ return true;
+ }
+};
+
+class LLToolsSelectBySurrounding : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLSelectMgr::sRectSelectInclusive = !LLSelectMgr::sRectSelectInclusive;
+
+ gSavedSettings.setBOOL("RectangleSelectInclusive", LLSelectMgr::sRectSelectInclusive);
+ return true;
+ }
+};
+
+class LLToolsShowHiddenSelection : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ // TomY TODO Merge these
+ LLSelectMgr::sRenderHiddenSelections = !LLSelectMgr::sRenderHiddenSelections;
+
+ gSavedSettings.setBOOL("RenderHiddenSelections", LLSelectMgr::sRenderHiddenSelections);
+ return true;
+ }
+};
+
+class LLToolsShowSelectionLightRadius : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ // TomY TODO merge these
+ LLSelectMgr::sRenderLightRadius = !LLSelectMgr::sRenderLightRadius;
+
+ gSavedSettings.setBOOL("RenderLightRadius", LLSelectMgr::sRenderLightRadius);
+ return true;
+ }
+};
+
+class LLToolsEditLinkedParts : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ BOOL select_individuals = !gSavedSettings.getBOOL("EditLinkedParts");
+ gSavedSettings.setBOOL( "EditLinkedParts", select_individuals );
+ if (select_individuals)
+ {
+ LLSelectMgr::getInstance()->demoteSelectionToIndividuals();
+ }
+ else
+ {
+ LLSelectMgr::getInstance()->promoteSelectionToRoot();
+ }
+ return true;
+ }
+};
+
+void reload_vertex_shader(void *)
+{
+ //THIS WOULD BE AN AWESOME PLACE TO RELOAD SHADERS... just a thought - DaveP
+}
+
+void handle_dump_avatar_local_textures(void*)
+{
+ gAgentAvatarp->dumpLocalTextures();
+}
+
+void handle_dump_timers()
+{
+ LLFastTimer::dumpCurTimes();
+}
+
+void handle_debug_avatar_textures(void*)
+{
+ LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ if (objectp)
+ {
+ LLFloaterReg::showInstance( "avatar_textures", LLSD(objectp->getID()) );
+ }
+}
+
+void handle_grab_baked_texture(void* data)
+{
+ EBakedTextureIndex baked_tex_index = (EBakedTextureIndex)((intptr_t)data);
+ if (!isAgentAvatarValid()) return;
+
+ const LLUUID& asset_id = gAgentAvatarp->grabBakedTexture(baked_tex_index);
+ LL_INFOS("texture") << "Adding baked texture " << asset_id << " to inventory." << llendl;
+ LLAssetType::EType asset_type = LLAssetType::AT_TEXTURE;
+ LLInventoryType::EType inv_type = LLInventoryType::IT_TEXTURE;
+ const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(asset_type));
+ if(folder_id.notNull())
+ {
+ std::string name;
+ name = "Baked " + LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_tex_index)->mNameCapitalized + " Texture";
+
+ LLUUID item_id;
+ item_id.generate();
+ LLPermissions perm;
+ perm.init(gAgentID,
+ gAgentID,
+ LLUUID::null,
+ LLUUID::null);
+ U32 next_owner_perm = PERM_MOVE | PERM_TRANSFER;
+ perm.initMasks(PERM_ALL,
+ PERM_ALL,
+ PERM_NONE,
+ PERM_NONE,
+ next_owner_perm);
+ time_t creation_date_now = time_corrected();
+ LLPointer<LLViewerInventoryItem> item
+ = new LLViewerInventoryItem(item_id,
+ folder_id,
+ perm,
+ asset_id,
+ asset_type,
+ inv_type,
+ name,
+ LLStringUtil::null,
+ LLSaleInfo::DEFAULT,
+ LLInventoryItemFlags::II_FLAGS_NONE,
+ creation_date_now);
+
+ item->updateServer(TRUE);
+ gInventory.updateItem(item);
+ gInventory.notifyObservers();
+
+ // Show the preview panel for textures to let
+ // user know that the image is now in inventory.
+ LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel();
+ if(active_panel)
+ {
+ LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus();
+
+ active_panel->setSelection(item_id, TAKE_FOCUS_NO);
+ active_panel->openSelected();
+ //LLFloaterInventory::dumpSelectionInformation((void*)view);
+ // restore keyboard focus
+ gFocusMgr.setKeyboardFocus(focus_ctrl);
+ }
+ }
+ else
+ {
+ llwarns << "Can't find a folder to put it in" << llendl;
+ }
+}
+
+BOOL enable_grab_baked_texture(void* data)
+{
+ EBakedTextureIndex index = (EBakedTextureIndex)((intptr_t)data);
+ if (isAgentAvatarValid())
+ {
+ return gAgentAvatarp->canGrabBakedTexture(index);
+ }
+ return FALSE;
+}
+
+// Returns a pointer to the avatar give the UUID of the avatar OR of an attachment the avatar is wearing.
+// Returns NULL on failure.
+LLVOAvatar* find_avatar_from_object( LLViewerObject* object )
+{
+ if (object)
+ {
+ if( object->isAttachment() )
+ {
+ do
+ {
+ object = (LLViewerObject*) object->getParent();
+ }
+ while( object && !object->isAvatar() );
+ }
+ else if( !object->isAvatar() )
+ {
+ object = NULL;
+ }
+ }
+
+ return (LLVOAvatar*) object;
+}
+
+
+// Returns a pointer to the avatar give the UUID of the avatar OR of an attachment the avatar is wearing.
+// Returns NULL on failure.
+LLVOAvatar* find_avatar_from_object( const LLUUID& object_id )
+{
+ return find_avatar_from_object( gObjectList.findObject(object_id) );
+}
+
+
+void handle_disconnect_viewer(void *)
+{
+ LLAppViewer::instance()->forceDisconnect(LLTrans::getString("TestingDisconnect"));
+}
+
+void force_error_breakpoint(void *)
+{
+ LLAppViewer::instance()->forceErrorBreakpoint();
+}
+
+void force_error_llerror(void *)
+{
+ LLAppViewer::instance()->forceErrorLLError();
+}
+
+void force_error_bad_memory_access(void *)
+{
+ LLAppViewer::instance()->forceErrorBadMemoryAccess();
+}
+
+void force_error_infinite_loop(void *)
+{
+ LLAppViewer::instance()->forceErrorInfiniteLoop();
+}
+
+void force_error_software_exception(void *)
+{
+ LLAppViewer::instance()->forceErrorSoftwareException();
+}
+
+void force_error_driver_crash(void *)
+{
+ LLAppViewer::instance()->forceErrorDriverCrash();
+}
+
+class LLToolsUseSelectionForGrid : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLSelectMgr::getInstance()->clearGridObjects();
+ struct f : public LLSelectedObjectFunctor
+ {
+ virtual bool apply(LLViewerObject* objectp)
+ {
+ LLSelectMgr::getInstance()->addGridObject(objectp);
+ return true;
+ }
+ } func;
+ LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func);
+ LLSelectMgr::getInstance()->setGridMode(GRID_MODE_REF_OBJECT);
+ if (gFloaterTools)
+ {
+ gFloaterTools->mComboGridMode->setCurrentByIndex((S32)GRID_MODE_REF_OBJECT);
+ }
+ return true;
+ }
+};
+
+void handle_test_load_url(void*)
+{
+ LLWeb::loadURL("");
+ LLWeb::loadURL("hacker://www.google.com/");
+ LLWeb::loadURL("http");
+ LLWeb::loadURL("http://www.google.com/");
+}
+
+//
+// LLViewerMenuHolderGL
+//
+static LLDefaultChildRegistry::Register<LLViewerMenuHolderGL> r("menu_holder");
+
+LLViewerMenuHolderGL::LLViewerMenuHolderGL(const LLViewerMenuHolderGL::Params& p)
+: LLMenuHolderGL(p)
+{}
+
+BOOL LLViewerMenuHolderGL::hideMenus()
+{
+ BOOL handled = FALSE;
+
+ if (LLMenuHolderGL::hideMenus())
+ {
+ LLToolPie::instance().blockClickToWalk();
+ handled = TRUE;
+ }
+
+ // drop pie menu selection
+ mParcelSelection = NULL;
+ mObjectSelection = NULL;
+
+ if (gMenuBarView)
+ {
+ gMenuBarView->clearHoverItem();
+ gMenuBarView->resetMenuTrigger();
+ }
+
+ return handled;
+}
+
+void LLViewerMenuHolderGL::setParcelSelection(LLSafeHandle<LLParcelSelection> selection)
+{
+ mParcelSelection = selection;
+}
+
+void LLViewerMenuHolderGL::setObjectSelection(LLSafeHandle<LLObjectSelection> selection)
+{
+ mObjectSelection = selection;
+}
+
+
+const LLRect LLViewerMenuHolderGL::getMenuRect() const
+{
+ return LLRect(0, getRect().getHeight() - MENU_BAR_HEIGHT, getRect().getWidth(), STATUS_BAR_HEIGHT);
+}
+
+void handle_web_browser_test(const LLSD& param)
+{
+ std::string url = param.asString();
+ if (url.empty())
+ {
+ url = "about:blank";
+ }
+ LLWeb::loadURLInternal(url);
+}
+
+void handle_web_content_test(const LLSD& param)
+{
+ std::string url = param.asString();
+ LLWeb::loadWebURLInternal(url);
+}
+
+void handle_buy_currency_test(void*)
+{
+ std::string url =
+ "http://sarahd-sl-13041.webdev.lindenlab.com/app/lindex/index.php?agent_id=[AGENT_ID]&secure_session_id=[SESSION_ID]&lang=[LANGUAGE]";
+
+ LLStringUtil::format_map_t replace;
+ replace["[AGENT_ID]"] = gAgent.getID().asString();
+ replace["[SESSION_ID]"] = gAgent.getSecureSessionID().asString();
+ replace["[LANGUAGE]"] = LLUI::getLanguage();
+ LLStringUtil::format(url, replace);
+
+ llinfos << "buy currency url " << url << llendl;
+
+ LLFloaterReg::showInstance("buy_currency_html", LLSD(url));
+}
+
+void handle_rebake_textures(void*)
+{
+ if (!isAgentAvatarValid()) return;
+
+ // Slam pending upload count to "unstick" things
+ bool slam_for_debug = true;
+ gAgentAvatarp->forceBakeAllTextures(slam_for_debug);
+}
+
+void toggle_visibility(void* user_data)
+{
+ LLView* viewp = (LLView*)user_data;
+ viewp->setVisible(!viewp->getVisible());
+}
+
+BOOL get_visibility(void* user_data)
+{
+ LLView* viewp = (LLView*)user_data;
+ return viewp->getVisible();
+}
+
+// TomY TODO: Get rid of these?
+class LLViewShowHoverTips : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gSavedSettings.setBOOL("ShowHoverTips", !gSavedSettings.getBOOL("ShowHoverTips"));
+ return true;
+ }
+};
+
+class LLViewCheckShowHoverTips : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gSavedSettings.getBOOL("ShowHoverTips");
+ return new_value;
+ }
+};
+
+// TomY TODO: Get rid of these?
+class LLViewHighlightTransparent : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha;
+ return true;
+ }
+};
+
+class LLViewCheckHighlightTransparent : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLDrawPoolAlpha::sShowDebugAlpha;
+ return new_value;
+ }
+};
+
+class LLViewBeaconWidth : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string width = userdata.asString();
+ if(width == "1")
+ {
+ gSavedSettings.setS32("DebugBeaconLineWidth", 1);
+ }
+ else if(width == "4")
+ {
+ gSavedSettings.setS32("DebugBeaconLineWidth", 4);
+ }
+ else if(width == "16")
+ {
+ gSavedSettings.setS32("DebugBeaconLineWidth", 16);
+ }
+ else if(width == "32")
+ {
+ gSavedSettings.setS32("DebugBeaconLineWidth", 32);
+ }
+
+ return true;
+ }
+};
+
+
+class LLViewToggleBeacon : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string beacon = userdata.asString();
+ if (beacon == "scriptsbeacon")
+ {
+ LLPipeline::toggleRenderScriptedBeacons(NULL);
+ gSavedSettings.setBOOL( "scriptsbeacon", LLPipeline::getRenderScriptedBeacons(NULL) );
+ // toggle the other one off if it's on
+ if (LLPipeline::getRenderScriptedBeacons(NULL) && LLPipeline::getRenderScriptedTouchBeacons(NULL))
+ {
+ LLPipeline::toggleRenderScriptedTouchBeacons(NULL);
+ gSavedSettings.setBOOL( "scripttouchbeacon", LLPipeline::getRenderScriptedTouchBeacons(NULL) );
+ }
+ }
+ else if (beacon == "physicalbeacon")
+ {
+ LLPipeline::toggleRenderPhysicalBeacons(NULL);
+ gSavedSettings.setBOOL( "physicalbeacon", LLPipeline::getRenderPhysicalBeacons(NULL) );
+ }
+ else if (beacon == "soundsbeacon")
+ {
+ LLPipeline::toggleRenderSoundBeacons(NULL);
+ gSavedSettings.setBOOL( "soundsbeacon", LLPipeline::getRenderSoundBeacons(NULL) );
+ }
+ else if (beacon == "particlesbeacon")
+ {
+ LLPipeline::toggleRenderParticleBeacons(NULL);
+ gSavedSettings.setBOOL( "particlesbeacon", LLPipeline::getRenderParticleBeacons(NULL) );
+ }
+ else if (beacon == "scripttouchbeacon")
+ {
+ LLPipeline::toggleRenderScriptedTouchBeacons(NULL);
+ gSavedSettings.setBOOL( "scripttouchbeacon", LLPipeline::getRenderScriptedTouchBeacons(NULL) );
+ // toggle the other one off if it's on
+ if (LLPipeline::getRenderScriptedBeacons(NULL) && LLPipeline::getRenderScriptedTouchBeacons(NULL))
+ {
+ LLPipeline::toggleRenderScriptedBeacons(NULL);
+ gSavedSettings.setBOOL( "scriptsbeacon", LLPipeline::getRenderScriptedBeacons(NULL) );
+ }
+ }
+ else if (beacon == "renderbeacons")
+ {
+ LLPipeline::toggleRenderBeacons(NULL);
+ gSavedSettings.setBOOL( "renderbeacons", LLPipeline::getRenderBeacons(NULL) );
+ // toggle the other one on if it's not
+ if (!LLPipeline::getRenderBeacons(NULL) && !LLPipeline::getRenderHighlights(NULL))
+ {
+ LLPipeline::toggleRenderHighlights(NULL);
+ gSavedSettings.setBOOL( "renderhighlights", LLPipeline::getRenderHighlights(NULL) );
+ }
+ }
+ else if (beacon == "renderhighlights")
+ {
+ LLPipeline::toggleRenderHighlights(NULL);
+ gSavedSettings.setBOOL( "renderhighlights", LLPipeline::getRenderHighlights(NULL) );
+ // toggle the other one on if it's not
+ if (!LLPipeline::getRenderBeacons(NULL) && !LLPipeline::getRenderHighlights(NULL))
+ {
+ LLPipeline::toggleRenderBeacons(NULL);
+ gSavedSettings.setBOOL( "renderbeacons", LLPipeline::getRenderBeacons(NULL) );
+ }
+ }
+
+ return true;
+ }
+};
+
+class LLViewCheckBeaconEnabled : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string beacon = userdata.asString();
+ bool new_value = false;
+ if (beacon == "scriptsbeacon")
+ {
+ new_value = gSavedSettings.getBOOL( "scriptsbeacon");
+ LLPipeline::setRenderScriptedBeacons(new_value);
+ }
+ else if (beacon == "physicalbeacon")
+ {
+ new_value = gSavedSettings.getBOOL( "physicalbeacon");
+ LLPipeline::setRenderPhysicalBeacons(new_value);
+ }
+ else if (beacon == "soundsbeacon")
+ {
+ new_value = gSavedSettings.getBOOL( "soundsbeacon");
+ LLPipeline::setRenderSoundBeacons(new_value);
+ }
+ else if (beacon == "particlesbeacon")
+ {
+ new_value = gSavedSettings.getBOOL( "particlesbeacon");
+ LLPipeline::setRenderParticleBeacons(new_value);
+ }
+ else if (beacon == "scripttouchbeacon")
+ {
+ new_value = gSavedSettings.getBOOL( "scripttouchbeacon");
+ LLPipeline::setRenderScriptedTouchBeacons(new_value);
+ }
+ else if (beacon == "renderbeacons")
+ {
+ new_value = gSavedSettings.getBOOL( "renderbeacons");
+ LLPipeline::setRenderBeacons(new_value);
+ }
+ else if (beacon == "renderhighlights")
+ {
+ new_value = gSavedSettings.getBOOL( "renderhighlights");
+ LLPipeline::setRenderHighlights(new_value);
+ }
+ return new_value;
+ }
+};
+
+class LLViewToggleRenderType : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string type = userdata.asString();
+ if (type == "hideparticles")
+ {
+ LLPipeline::toggleRenderType(LLPipeline::RENDER_TYPE_PARTICLES);
+ }
+ return true;
+ }
+};
+
+class LLViewCheckRenderType : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string type = userdata.asString();
+ bool new_value = false;
+ if (type == "hideparticles")
+ {
+ new_value = LLPipeline::toggleRenderTypeControlNegated((void *)LLPipeline::RENDER_TYPE_PARTICLES);
+ }
+ return new_value;
+ }
+};
+
+class LLViewShowHUDAttachments : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLPipeline::sShowHUDAttachments = !LLPipeline::sShowHUDAttachments;
+ return true;
+ }
+};
+
+class LLViewCheckHUDAttachments : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLPipeline::sShowHUDAttachments;
+ return new_value;
+ }
+};
+
+class LLEditEnableTakeOff : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string clothing = userdata.asString();
+ LLWearableType::EType type = LLWearableType::typeNameToType(clothing);
+ if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT)
+ return LLAgentWearables::selfHasWearable(type);
+ return false;
+ }
+};
+
+class LLEditTakeOff : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string clothing = userdata.asString();
+ if (clothing == "all")
+ LLWearableBridge::removeAllClothesFromAvatar();
+ else
+ {
+ LLWearableType::EType type = LLWearableType::typeNameToType(clothing);
+ if (type >= LLWearableType::WT_SHAPE
+ && type < LLWearableType::WT_COUNT
+ && (gAgentWearables.getWearableCount(type) > 0))
+ {
+ // MULTI-WEARABLES: assuming user wanted to remove top shirt.
+ U32 wearable_index = gAgentWearables.getWearableCount(type) - 1;
+ LLViewerInventoryItem *item = dynamic_cast<LLViewerInventoryItem*>(gAgentWearables.getWearableInventoryItem(type,wearable_index));
+ LLWearableBridge::removeItemFromAvatar(item);
+ }
+
+ }
+ return true;
+ }
+};
+
+class LLToolsSelectTool : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string tool_name = userdata.asString();
+ if (tool_name == "focus")
+ {
+ LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(1);
+ }
+ else if (tool_name == "move")
+ {
+ LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(2);
+ }
+ else if (tool_name == "edit")
+ {
+ LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(3);
+ }
+ else if (tool_name == "create")
+ {
+ LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(4);
+ }
+ else if (tool_name == "land")
+ {
+ LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(5);
+ }
+ return true;
+ }
+};
+
+/// WINDLIGHT callbacks
+class LLWorldEnvSettings : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string tod = userdata.asString();
+ LLVector3 sun_direction;
+
+ if (tod == "editor")
+ {
+ // if not there or is hidden, show it
+ LLFloaterReg::toggleInstance("env_settings");
+ return true;
+ }
+
+ if (tod == "sunrise")
+ {
+ // set the value, turn off animation
+ LLWLParamManager::instance()->mAnimator.setDayTime(0.25);
+ LLWLParamManager::instance()->mAnimator.mIsRunning = false;
+ LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+
+ // then call update once
+ LLWLParamManager::instance()->mAnimator.update(
+ LLWLParamManager::instance()->mCurParams);
+ }
+ else if (tod == "noon")
+ {
+ // set the value, turn off animation
+ LLWLParamManager::instance()->mAnimator.setDayTime(0.567);
+ LLWLParamManager::instance()->mAnimator.mIsRunning = false;
+ LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+
+ // then call update once
+ LLWLParamManager::instance()->mAnimator.update(
+ LLWLParamManager::instance()->mCurParams);
+ }
+ else if (tod == "sunset")
+ {
+ // set the value, turn off animation
+ LLWLParamManager::instance()->mAnimator.setDayTime(0.75);
+ LLWLParamManager::instance()->mAnimator.mIsRunning = false;
+ LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+
+ // then call update once
+ LLWLParamManager::instance()->mAnimator.update(
+ LLWLParamManager::instance()->mCurParams);
+ }
+ else if (tod == "midnight")
+ {
+ // set the value, turn off animation
+ LLWLParamManager::instance()->mAnimator.setDayTime(0.0);
+ LLWLParamManager::instance()->mAnimator.mIsRunning = false;
+ LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+
+ // then call update once
+ LLWLParamManager::instance()->mAnimator.update(
+ LLWLParamManager::instance()->mCurParams);
+ }
+ else
+ {
+ LLWLParamManager::instance()->mAnimator.mIsRunning = true;
+ LLWLParamManager::instance()->mAnimator.mUseLindenTime = true;
+ }
+ return true;
+ }
+};
+
+/// Water Menu callbacks
+class LLWorldWaterSettings : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLFloaterReg::toggleInstance("env_water");
+ return true;
+ }
+};
+
+/// Post-Process callbacks
+class LLWorldPostProcess : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLFloaterReg::showInstance("env_post_process");
+ return true;
+ }
+};
+
+/// Day Cycle callbacks
+class LLWorldDayCycle : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLFloaterReg::showInstance("env_day_cycle");
+ return true;
+ }
+};
+
+class LLWorldToggleMovementControls : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLBottomTray::getInstance()->toggleMovementControls();
+ return true;
+ }
+};
+
+class LLWorldToggleCameraControls : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLBottomTray::getInstance()->toggleCameraControls();
+ return true;
+ }
+};
+
+void handle_flush_name_caches()
+{
+ // Toggle display names on and off to flush
+ bool use_display_names = LLAvatarNameCache::useDisplayNames();
+ LLAvatarNameCache::setUseDisplayNames(!use_display_names);
+ LLAvatarNameCache::setUseDisplayNames(use_display_names);
+
+ if (gCacheName) gCacheName->clear();
+}
+
+class LLUploadCostCalculator : public view_listener_t
+{
+ std::string mCostStr;
+
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string menu_name = userdata.asString();
+ gMenuHolder->childSetLabelArg(menu_name, "[COST]", mCostStr);
+
+ return true;
+ }
+
+ void calculateCost();
+
+public:
+ LLUploadCostCalculator()
+ {
+ calculateCost();
+ }
+};
+
+class LLToggleUIHints : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool ui_hints_enabled = gSavedSettings.getBOOL("EnableUIHints");
+ // toggle
+ ui_hints_enabled = !ui_hints_enabled;
+ gSavedSettings.setBOOL("EnableUIHints", ui_hints_enabled);
+ return true;
+ }
+};
+
+void LLUploadCostCalculator::calculateCost()
+{
+ S32 upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
+
+ // getPriceUpload() returns -1 if no data available yet.
+ if(upload_cost >= 0)
+ {
+ mCostStr = llformat("%d", upload_cost);
+ }
+ else
+ {
+ mCostStr = llformat("%d", gSavedSettings.getU32("DefaultUploadCost"));
+ }
+}
+
+void show_navbar_context_menu(LLView* ctrl, S32 x, S32 y)
+{
+ static LLMenuGL* show_navbar_context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_hide_navbar.xml",
+ gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ if(gMenuHolder->hasVisibleMenu())
+ {
+ gMenuHolder->hideMenus();
+ }
+ show_navbar_context_menu->buildDrawLabels();
+ show_navbar_context_menu->updateParent(LLMenuGL::sMenuContainer);
+ LLMenuGL::showPopup(ctrl, show_navbar_context_menu, x, y);
+}
+
+void show_topinfobar_context_menu(LLView* ctrl, S32 x, S32 y)
+{
+ static LLMenuGL* show_topbarinfo_context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_topinfobar.xml",
+ gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+
+ LLMenuItemGL* landmark_item = show_topbarinfo_context_menu->getChild<LLMenuItemGL>("Landmark");
+ if (!LLLandmarkActions::landmarkAlreadyExists())
+ {
+ landmark_item->setLabel(LLTrans::getString("AddLandmarkNavBarMenu"));
+ }
+ else
+ {
+ landmark_item->setLabel(LLTrans::getString("EditLandmarkNavBarMenu"));
+ }
+
+ if(gMenuHolder->hasVisibleMenu())
+ {
+ gMenuHolder->hideMenus();
+ }
+
+ show_topbarinfo_context_menu->buildDrawLabels();
+ show_topbarinfo_context_menu->updateParent(LLMenuGL::sMenuContainer);
+ LLMenuGL::showPopup(ctrl, show_topbarinfo_context_menu, x, y);
+}
+
+void initialize_edit_menu()
+{
+ view_listener_t::addMenu(new LLEditUndo(), "Edit.Undo");
+ view_listener_t::addMenu(new LLEditRedo(), "Edit.Redo");
+ view_listener_t::addMenu(new LLEditCut(), "Edit.Cut");
+ view_listener_t::addMenu(new LLEditCopy(), "Edit.Copy");
+ view_listener_t::addMenu(new LLEditPaste(), "Edit.Paste");
+ view_listener_t::addMenu(new LLEditDelete(), "Edit.Delete");
+ view_listener_t::addMenu(new LLEditSelectAll(), "Edit.SelectAll");
+ view_listener_t::addMenu(new LLEditDeselect(), "Edit.Deselect");
+ view_listener_t::addMenu(new LLEditDuplicate(), "Edit.Duplicate");
+ view_listener_t::addMenu(new LLEditTakeOff(), "Edit.TakeOff");
+ view_listener_t::addMenu(new LLEditEnableUndo(), "Edit.EnableUndo");
+ view_listener_t::addMenu(new LLEditEnableRedo(), "Edit.EnableRedo");
+ view_listener_t::addMenu(new LLEditEnableCut(), "Edit.EnableCut");
+ view_listener_t::addMenu(new LLEditEnableCopy(), "Edit.EnableCopy");
+ view_listener_t::addMenu(new LLEditEnablePaste(), "Edit.EnablePaste");
+ view_listener_t::addMenu(new LLEditEnableDelete(), "Edit.EnableDelete");
+ view_listener_t::addMenu(new LLEditEnableSelectAll(), "Edit.EnableSelectAll");
+ view_listener_t::addMenu(new LLEditEnableDeselect(), "Edit.EnableDeselect");
+ view_listener_t::addMenu(new LLEditEnableDuplicate(), "Edit.EnableDuplicate");
+
+}
+
+void initialize_menus()
+{
+ // A parameterized event handler used as ctrl-8/9/0 zoom controls below.
+ class LLZoomer : public view_listener_t
+ {
+ public:
+ // The "mult" parameter says whether "val" is a multiplier or used to set the value.
+ LLZoomer(F32 val, bool mult=true) : mVal(val), mMult(mult) {}
+ bool handleEvent(const LLSD& userdata)
+ {
+ F32 new_fov_rad = mMult ? LLViewerCamera::getInstance()->getDefaultFOV() * mVal : mVal;
+ LLViewerCamera::getInstance()->setDefaultFOV(new_fov_rad);
+ gSavedSettings.setF32("CameraAngle", LLViewerCamera::getInstance()->getView()); // setView may have clamped it.
+ return true;
+ }
+ private:
+ F32 mVal;
+ bool mMult;
+ };
+
+ LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar();
+ LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar();
+
+ // Generic enable and visible
+ // Don't prepend MenuName.Foo because these can be used in any menu.
+ enable.add("IsGodCustomerService", boost::bind(&is_god_customer_service));
+
+ view_listener_t::addEnable(new LLUploadCostCalculator(), "Upload.CalculateCosts");
+
+ // Agent
+ commit.add("Agent.toggleFlying", boost::bind(&LLAgent::toggleFlying));
+ enable.add("Agent.enableFlying", boost::bind(&LLAgent::enableFlying));
+
+ // File menu
+ init_menu_file();
+
+ view_listener_t::addMenu(new LLEditEnableTakeOff(), "Edit.EnableTakeOff");
+ view_listener_t::addMenu(new LLEditEnableCustomizeAvatar(), "Edit.EnableCustomizeAvatar");
+ view_listener_t::addMenu(new LLEnableEditShape(), "Edit.EnableEditShape");
+ commit.add("CustomizeAvatar", boost::bind(&handle_customize_avatar));
+ commit.add("EditOutfit", boost::bind(&handle_edit_outfit));
+ commit.add("EditShape", boost::bind(&handle_edit_shape));
+
+ // View menu
+ view_listener_t::addMenu(new LLViewMouselook(), "View.Mouselook");
+ view_listener_t::addMenu(new LLViewJoystickFlycam(), "View.JoystickFlycam");
+ view_listener_t::addMenu(new LLViewResetView(), "View.ResetView");
+ view_listener_t::addMenu(new LLViewLookAtLastChatter(), "View.LookAtLastChatter");
+ view_listener_t::addMenu(new LLViewShowHoverTips(), "View.ShowHoverTips");
+ view_listener_t::addMenu(new LLViewHighlightTransparent(), "View.HighlightTransparent");
+ view_listener_t::addMenu(new LLViewToggleRenderType(), "View.ToggleRenderType");
+ view_listener_t::addMenu(new LLViewShowHUDAttachments(), "View.ShowHUDAttachments");
+ view_listener_t::addMenu(new LLZoomer(1.2f), "View.ZoomOut");
+ view_listener_t::addMenu(new LLZoomer(1/1.2f), "View.ZoomIn");
+ view_listener_t::addMenu(new LLZoomer(DEFAULT_FIELD_OF_VIEW, false), "View.ZoomDefault");
+ view_listener_t::addMenu(new LLViewDefaultUISize(), "View.DefaultUISize");
+
+ view_listener_t::addMenu(new LLViewEnableMouselook(), "View.EnableMouselook");
+ view_listener_t::addMenu(new LLViewEnableJoystickFlycam(), "View.EnableJoystickFlycam");
+ view_listener_t::addMenu(new LLViewEnableLastChatter(), "View.EnableLastChatter");
+
+ view_listener_t::addMenu(new LLViewCheckJoystickFlycam(), "View.CheckJoystickFlycam");
+ view_listener_t::addMenu(new LLViewCheckShowHoverTips(), "View.CheckShowHoverTips");
+ view_listener_t::addMenu(new LLViewCheckHighlightTransparent(), "View.CheckHighlightTransparent");
+ view_listener_t::addMenu(new LLViewCheckRenderType(), "View.CheckRenderType");
+ view_listener_t::addMenu(new LLViewCheckHUDAttachments(), "View.CheckHUDAttachments");
+
+ // Me > Movement
+ view_listener_t::addMenu(new LLAdvancedAgentFlyingInfo(), "Agent.getFlying");
+
+ // World menu
+ commit.add("World.Chat", boost::bind(&handle_chat, (void*)NULL));
+ view_listener_t::addMenu(new LLWorldAlwaysRun(), "World.AlwaysRun");
+ view_listener_t::addMenu(new LLWorldCreateLandmark(), "World.CreateLandmark");
+ view_listener_t::addMenu(new LLWorldPlaceProfile(), "World.PlaceProfile");
+ view_listener_t::addMenu(new LLWorldSetHomeLocation(), "World.SetHomeLocation");
+ view_listener_t::addMenu(new LLWorldTeleportHome(), "World.TeleportHome");
+ view_listener_t::addMenu(new LLWorldSetAway(), "World.SetAway");
+ view_listener_t::addMenu(new LLWorldSetBusy(), "World.SetBusy");
+
+ view_listener_t::addMenu(new LLWorldEnableCreateLandmark(), "World.EnableCreateLandmark");
+ view_listener_t::addMenu(new LLWorldEnableSetHomeLocation(), "World.EnableSetHomeLocation");
+ view_listener_t::addMenu(new LLWorldEnableTeleportHome(), "World.EnableTeleportHome");
+ view_listener_t::addMenu(new LLWorldEnableBuyLand(), "World.EnableBuyLand");
+
+ view_listener_t::addMenu(new LLWorldCheckAlwaysRun(), "World.CheckAlwaysRun");
+
+ view_listener_t::addMenu(new LLWorldEnvSettings(), "World.EnvSettings");
+ view_listener_t::addMenu(new LLWorldWaterSettings(), "World.WaterSettings");
+ view_listener_t::addMenu(new LLWorldPostProcess(), "World.PostProcess");
+ view_listener_t::addMenu(new LLWorldDayCycle(), "World.DayCycle");
+
+ view_listener_t::addMenu(new LLWorldToggleMovementControls(), "World.Toggle.MovementControls");
+ view_listener_t::addMenu(new LLWorldToggleCameraControls(), "World.Toggle.CameraControls");
+
+ // Tools menu
+ view_listener_t::addMenu(new LLToolsSelectTool(), "Tools.SelectTool");
+ view_listener_t::addMenu(new LLToolsSelectOnlyMyObjects(), "Tools.SelectOnlyMyObjects");
+ view_listener_t::addMenu(new LLToolsSelectOnlyMovableObjects(), "Tools.SelectOnlyMovableObjects");
+ view_listener_t::addMenu(new LLToolsSelectBySurrounding(), "Tools.SelectBySurrounding");
+ view_listener_t::addMenu(new LLToolsShowHiddenSelection(), "Tools.ShowHiddenSelection");
+ view_listener_t::addMenu(new LLToolsShowSelectionLightRadius(), "Tools.ShowSelectionLightRadius");
+ view_listener_t::addMenu(new LLToolsEditLinkedParts(), "Tools.EditLinkedParts");
+ view_listener_t::addMenu(new LLToolsSnapObjectXY(), "Tools.SnapObjectXY");
+ view_listener_t::addMenu(new LLToolsUseSelectionForGrid(), "Tools.UseSelectionForGrid");
+ view_listener_t::addMenu(new LLToolsSelectNextPart(), "Tools.SelectNextPart");
+ commit.add("Tools.Link", boost::bind(&LLSelectMgr::linkObjects, LLSelectMgr::getInstance()));
+ commit.add("Tools.Unlink", boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance()));
+ view_listener_t::addMenu(new LLToolsStopAllAnimations(), "Tools.StopAllAnimations");
+ view_listener_t::addMenu(new LLToolsReleaseKeys(), "Tools.ReleaseKeys");
+ view_listener_t::addMenu(new LLToolsEnableReleaseKeys(), "Tools.EnableReleaseKeys");
+ commit.add("Tools.LookAtSelection", boost::bind(&handle_look_at_selection, _2));
+ commit.add("Tools.BuyOrTake", boost::bind(&handle_buy_or_take));
+ commit.add("Tools.TakeCopy", boost::bind(&handle_take_copy));
+ view_listener_t::addMenu(new LLToolsSaveToInventory(), "Tools.SaveToInventory");
+ view_listener_t::addMenu(new LLToolsSaveToObjectInventory(), "Tools.SaveToObjectInventory");
+ view_listener_t::addMenu(new LLToolsSelectedScriptAction(), "Tools.SelectedScriptAction");
+
+ view_listener_t::addMenu(new LLToolsEnableToolNotPie(), "Tools.EnableToolNotPie");
+ view_listener_t::addMenu(new LLToolsEnableSelectNextPart(), "Tools.EnableSelectNextPart");
+ enable.add("Tools.EnableLink", boost::bind(&LLSelectMgr::enableLinkObjects, LLSelectMgr::getInstance()));
+ enable.add("Tools.EnableUnlink", boost::bind(&LLSelectMgr::enableUnlinkObjects, LLSelectMgr::getInstance()));
+ view_listener_t::addMenu(new LLToolsEnableBuyOrTake(), "Tools.EnableBuyOrTake");
+ enable.add("Tools.EnableTakeCopy", boost::bind(&enable_object_take_copy));
+ enable.add("Tools.VisibleBuyObject", boost::bind(&tools_visible_buy_object));
+ enable.add("Tools.VisibleTakeObject", boost::bind(&tools_visible_take_object));
+ view_listener_t::addMenu(new LLToolsEnableSaveToInventory(), "Tools.EnableSaveToInventory");
+ view_listener_t::addMenu(new LLToolsEnableSaveToObjectInventory(), "Tools.EnableSaveToObjectInventory");
+
+ // Help menu
+ // most items use the ShowFloater method
+
+ // Advanced menu
+ view_listener_t::addMenu(new LLAdvancedToggleConsole(), "Advanced.ToggleConsole");
+ view_listener_t::addMenu(new LLAdvancedCheckConsole(), "Advanced.CheckConsole");
+ view_listener_t::addMenu(new LLAdvancedDumpInfoToConsole(), "Advanced.DumpInfoToConsole");
+
+ // Advanced > HUD Info
+ view_listener_t::addMenu(new LLAdvancedToggleHUDInfo(), "Advanced.ToggleHUDInfo");
+ view_listener_t::addMenu(new LLAdvancedCheckHUDInfo(), "Advanced.CheckHUDInfo");
+
+ // Advanced Other Settings
+ view_listener_t::addMenu(new LLAdvancedClearGroupCache(), "Advanced.ClearGroupCache");
+
+ // Advanced > Render > Types
+ view_listener_t::addMenu(new LLAdvancedToggleRenderType(), "Advanced.ToggleRenderType");
+ view_listener_t::addMenu(new LLAdvancedCheckRenderType(), "Advanced.CheckRenderType");
+
+ //// Advanced > Render > Features
+ view_listener_t::addMenu(new LLAdvancedToggleFeature(), "Advanced.ToggleFeature");
+ view_listener_t::addMenu(new LLAdvancedCheckFeature(), "Advanced.CheckFeature");
+ // Advanced > Render > Info Displays
+ view_listener_t::addMenu(new LLAdvancedToggleInfoDisplay(), "Advanced.ToggleInfoDisplay");
+ view_listener_t::addMenu(new LLAdvancedCheckInfoDisplay(), "Advanced.CheckInfoDisplay");
+ view_listener_t::addMenu(new LLAdvancedSelectedTextureInfo(), "Advanced.SelectedTextureInfo");
+ view_listener_t::addMenu(new LLAdvancedToggleWireframe(), "Advanced.ToggleWireframe");
+ view_listener_t::addMenu(new LLAdvancedCheckWireframe(), "Advanced.CheckWireframe");
+ // Develop > Render
+ view_listener_t::addMenu(new LLAdvancedToggleTextureAtlas(), "Advanced.ToggleTextureAtlas");
+ view_listener_t::addMenu(new LLAdvancedCheckTextureAtlas(), "Advanced.CheckTextureAtlas");
+ view_listener_t::addMenu(new LLAdvancedEnableObjectObjectOcclusion(), "Advanced.EnableObjectObjectOcclusion");
+ view_listener_t::addMenu(new LLAdvancedEnableRenderFBO(), "Advanced.EnableRenderFBO");
+ view_listener_t::addMenu(new LLAdvancedEnableRenderDeferred(), "Advanced.EnableRenderDeferred");
+ view_listener_t::addMenu(new LLAdvancedEnableRenderDeferredOptions(), "Advanced.EnableRenderDeferredOptions");
+ view_listener_t::addMenu(new LLAdvancedToggleRandomizeFramerate(), "Advanced.ToggleRandomizeFramerate");
+ view_listener_t::addMenu(new LLAdvancedCheckRandomizeFramerate(), "Advanced.CheckRandomizeFramerate");
+ view_listener_t::addMenu(new LLAdvancedTogglePeriodicSlowFrame(), "Advanced.TogglePeriodicSlowFrame");
+ view_listener_t::addMenu(new LLAdvancedCheckPeriodicSlowFrame(), "Advanced.CheckPeriodicSlowFrame");
+ view_listener_t::addMenu(new LLAdvancedVectorizePerfTest(), "Advanced.VectorizePerfTest");
+ view_listener_t::addMenu(new LLAdvancedToggleFrameTest(), "Advanced.ToggleFrameTest");
+ view_listener_t::addMenu(new LLAdvancedCheckFrameTest(), "Advanced.CheckFrameTest");
+ view_listener_t::addMenu(new LLAdvancedHandleAttachedLightParticles(), "Advanced.HandleAttachedLightParticles");
+ view_listener_t::addMenu(new LLAdvancedCheckRenderShadowOption(), "Advanced.CheckRenderShadowOption");
+ view_listener_t::addMenu(new LLAdvancedClickRenderShadowOption(), "Advanced.ClickRenderShadowOption");
+
+
+ #ifdef TOGGLE_HACKED_GODLIKE_VIEWER
+ view_listener_t::addMenu(new LLAdvancedHandleToggleHackedGodmode(), "Advanced.HandleToggleHackedGodmode");
+ view_listener_t::addMenu(new LLAdvancedCheckToggleHackedGodmode(), "Advanced.CheckToggleHackedGodmode");
+ view_listener_t::addMenu(new LLAdvancedEnableToggleHackedGodmode(), "Advanced.EnableToggleHackedGodmode");
+ #endif
+
+ // Advanced > World
+ view_listener_t::addMenu(new LLAdvancedDumpScriptedCamera(), "Advanced.DumpScriptedCamera");
+ view_listener_t::addMenu(new LLAdvancedDumpRegionObjectCache(), "Advanced.DumpRegionObjectCache");
+
+ // Advanced > UI
+ commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); // sigh! this one opens the MEDIA browser
+ commit.add("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2)); // this one opens the Web Content floater
+ view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest");
+ view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr");
+ view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory");
+ commit.add("Advanced.DumpTimers", boost::bind(&handle_dump_timers) );
+ commit.add("Advanced.DumpFocusHolder", boost::bind(&handle_dump_focus) );
+ view_listener_t::addMenu(new LLAdvancedPrintSelectedObjectInfo(), "Advanced.PrintSelectedObjectInfo");
+ view_listener_t::addMenu(new LLAdvancedPrintAgentInfo(), "Advanced.PrintAgentInfo");
+ view_listener_t::addMenu(new LLAdvancedPrintTextureMemoryStats(), "Advanced.PrintTextureMemoryStats");
+ view_listener_t::addMenu(new LLAdvancedToggleDebugClicks(), "Advanced.ToggleDebugClicks");
+ view_listener_t::addMenu(new LLAdvancedCheckDebugClicks(), "Advanced.CheckDebugClicks");
+ view_listener_t::addMenu(new LLAdvancedCheckDebugViews(), "Advanced.CheckDebugViews");
+ view_listener_t::addMenu(new LLAdvancedToggleDebugViews(), "Advanced.ToggleDebugViews");
+ view_listener_t::addMenu(new LLAdvancedToggleXUINameTooltips(), "Advanced.ToggleXUINameTooltips");
+ view_listener_t::addMenu(new LLAdvancedCheckXUINameTooltips(), "Advanced.CheckXUINameTooltips");
+ view_listener_t::addMenu(new LLAdvancedToggleDebugMouseEvents(), "Advanced.ToggleDebugMouseEvents");
+ view_listener_t::addMenu(new LLAdvancedCheckDebugMouseEvents(), "Advanced.CheckDebugMouseEvents");
+ view_listener_t::addMenu(new LLAdvancedToggleDebugKeys(), "Advanced.ToggleDebugKeys");
+ view_listener_t::addMenu(new LLAdvancedCheckDebugKeys(), "Advanced.CheckDebugKeys");
+ view_listener_t::addMenu(new LLAdvancedToggleDebugWindowProc(), "Advanced.ToggleDebugWindowProc");
+ view_listener_t::addMenu(new LLAdvancedCheckDebugWindowProc(), "Advanced.CheckDebugWindowProc");
+ commit.add("Advanced.ShowSideTray", boost::bind(&handle_show_side_tray));
+
+ // Advanced > XUI
+ commit.add("Advanced.ReloadColorSettings", boost::bind(&LLUIColorTable::loadFromSettings, LLUIColorTable::getInstance()));
+ view_listener_t::addMenu(new LLAdvancedToggleXUINames(), "Advanced.ToggleXUINames");
+ view_listener_t::addMenu(new LLAdvancedCheckXUINames(), "Advanced.CheckXUINames");
+ view_listener_t::addMenu(new LLAdvancedSendTestIms(), "Advanced.SendTestIMs");
+ commit.add("Advanced.FlushNameCaches", boost::bind(&handle_flush_name_caches));
+
+ // Advanced > Character > Grab Baked Texture
+ view_listener_t::addMenu(new LLAdvancedGrabBakedTexture(), "Advanced.GrabBakedTexture");
+ view_listener_t::addMenu(new LLAdvancedEnableGrabBakedTexture(), "Advanced.EnableGrabBakedTexture");
+
+ // Advanced > Character > Character Tests
+ view_listener_t::addMenu(new LLAdvancedAppearanceToXML(), "Advanced.AppearanceToXML");
+ view_listener_t::addMenu(new LLAdvancedToggleCharacterGeometry(), "Advanced.ToggleCharacterGeometry");
+
+ view_listener_t::addMenu(new LLAdvancedTestMale(), "Advanced.TestMale");
+ view_listener_t::addMenu(new LLAdvancedTestFemale(), "Advanced.TestFemale");
+ view_listener_t::addMenu(new LLAdvancedTogglePG(), "Advanced.TogglePG");
+
+ // Advanced > Character (toplevel)
+ view_listener_t::addMenu(new LLAdvancedForceParamsToDefault(), "Advanced.ForceParamsToDefault");
+ view_listener_t::addMenu(new LLAdvancedReloadVertexShader(), "Advanced.ReloadVertexShader");
+ view_listener_t::addMenu(new LLAdvancedToggleAnimationInfo(), "Advanced.ToggleAnimationInfo");
+ view_listener_t::addMenu(new LLAdvancedCheckAnimationInfo(), "Advanced.CheckAnimationInfo");
+ view_listener_t::addMenu(new LLAdvancedToggleShowLookAt(), "Advanced.ToggleShowLookAt");
+ view_listener_t::addMenu(new LLAdvancedCheckShowLookAt(), "Advanced.CheckShowLookAt");
+ view_listener_t::addMenu(new LLAdvancedToggleShowPointAt(), "Advanced.ToggleShowPointAt");
+ view_listener_t::addMenu(new LLAdvancedCheckShowPointAt(), "Advanced.CheckShowPointAt");
+ view_listener_t::addMenu(new LLAdvancedToggleDebugJointUpdates(), "Advanced.ToggleDebugJointUpdates");
+ view_listener_t::addMenu(new LLAdvancedCheckDebugJointUpdates(), "Advanced.CheckDebugJointUpdates");
+ view_listener_t::addMenu(new LLAdvancedToggleDisableLOD(), "Advanced.ToggleDisableLOD");
+ view_listener_t::addMenu(new LLAdvancedCheckDisableLOD(), "Advanced.CheckDisableLOD");
+ view_listener_t::addMenu(new LLAdvancedToggleDebugCharacterVis(), "Advanced.ToggleDebugCharacterVis");
+ view_listener_t::addMenu(new LLAdvancedCheckDebugCharacterVis(), "Advanced.CheckDebugCharacterVis");
+ view_listener_t::addMenu(new LLAdvancedDumpAttachments(), "Advanced.DumpAttachments");
+ view_listener_t::addMenu(new LLAdvancedRebakeTextures(), "Advanced.RebakeTextures");
+ view_listener_t::addMenu(new LLAdvancedDebugAvatarTextures(), "Advanced.DebugAvatarTextures");
+ view_listener_t::addMenu(new LLAdvancedDumpAvatarLocalTextures(), "Advanced.DumpAvatarLocalTextures");
+ // Advanced > Network
+ view_listener_t::addMenu(new LLAdvancedEnableMessageLog(), "Advanced.EnableMessageLog");
+ view_listener_t::addMenu(new LLAdvancedDisableMessageLog(), "Advanced.DisableMessageLog");
+ view_listener_t::addMenu(new LLAdvancedDropPacket(), "Advanced.DropPacket");
+
+ // Advanced > Recorder
+ view_listener_t::addMenu(new LLAdvancedAgentPilot(), "Advanced.AgentPilot");
+ view_listener_t::addMenu(new LLAdvancedToggleAgentPilotLoop(), "Advanced.ToggleAgentPilotLoop");
+ view_listener_t::addMenu(new LLAdvancedCheckAgentPilotLoop(), "Advanced.CheckAgentPilotLoop");
+
+ // Advanced > Debugging
+ view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint");
+ view_listener_t::addMenu(new LLAdvancedForceErrorLlerror(), "Advanced.ForceErrorLlerror");
+ view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccess(), "Advanced.ForceErrorBadMemoryAccess");
+ view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop");
+ view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareException(), "Advanced.ForceErrorSoftwareException");
+ view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDriverCrash");
+ view_listener_t::addMenu(new LLAdvancedForceErrorDisconnectViewer(), "Advanced.ForceErrorDisconnectViewer");
+
+ // Advanced (toplevel)
+ view_listener_t::addMenu(new LLAdvancedToggleShowObjectUpdates(), "Advanced.ToggleShowObjectUpdates");
+ view_listener_t::addMenu(new LLAdvancedCheckShowObjectUpdates(), "Advanced.CheckShowObjectUpdates");
+ view_listener_t::addMenu(new LLAdvancedCompressImage(), "Advanced.CompressImage");
+ view_listener_t::addMenu(new LLAdvancedShowDebugSettings(), "Advanced.ShowDebugSettings");
+ view_listener_t::addMenu(new LLAdvancedEnableViewAdminOptions(), "Advanced.EnableViewAdminOptions");
+ view_listener_t::addMenu(new LLAdvancedToggleViewAdminOptions(), "Advanced.ToggleViewAdminOptions");
+ view_listener_t::addMenu(new LLAdvancedCheckViewAdminOptions(), "Advanced.CheckViewAdminOptions");
+ view_listener_t::addMenu(new LLAdvancedRequestAdminStatus(), "Advanced.RequestAdminStatus");
+ view_listener_t::addMenu(new LLAdvancedLeaveAdminStatus(), "Advanced.LeaveAdminStatus");
+
+
+ // Admin >Object
+ view_listener_t::addMenu(new LLAdminForceTakeCopy(), "Admin.ForceTakeCopy");
+ view_listener_t::addMenu(new LLAdminHandleObjectOwnerSelf(), "Admin.HandleObjectOwnerSelf");
+ view_listener_t::addMenu(new LLAdminHandleObjectOwnerPermissive(), "Admin.HandleObjectOwnerPermissive");
+ view_listener_t::addMenu(new LLAdminHandleForceDelete(), "Admin.HandleForceDelete");
+ view_listener_t::addMenu(new LLAdminHandleObjectLock(), "Admin.HandleObjectLock");
+ view_listener_t::addMenu(new LLAdminHandleObjectAssetIDs(), "Admin.HandleObjectAssetIDs");
+
+ // Admin >Parcel
+ view_listener_t::addMenu(new LLAdminHandleForceParcelOwnerToMe(), "Admin.HandleForceParcelOwnerToMe");
+ view_listener_t::addMenu(new LLAdminHandleForceParcelToContent(), "Admin.HandleForceParcelToContent");
+ view_listener_t::addMenu(new LLAdminHandleClaimPublicLand(), "Admin.HandleClaimPublicLand");
+
+ // Admin >Region
+ view_listener_t::addMenu(new LLAdminHandleRegionDumpTempAssetData(), "Admin.HandleRegionDumpTempAssetData");
+ // Admin top level
+ view_listener_t::addMenu(new LLAdminOnSaveState(), "Admin.OnSaveState");
+
+ // Self context menu
+ view_listener_t::addMenu(new LLSelfStandUp(), "Self.StandUp");
+ enable.add("Self.EnableStandUp", boost::bind(&enable_standup_self));
+ view_listener_t::addMenu(new LLSelfSitDown(), "Self.SitDown");
+ enable.add("Self.EnableSitDown", boost::bind(&enable_sitdown_self));
+ view_listener_t::addMenu(new LLSelfRemoveAllAttachments(), "Self.RemoveAllAttachments");
+
+ view_listener_t::addMenu(new LLSelfEnableRemoveAllAttachments(), "Self.EnableRemoveAllAttachments");
+
+ // we don't use boost::bind directly to delay side tray construction
+ view_listener_t::addMenu( new LLTogglePanelPeopleTab(), "SideTray.PanelPeopleTab");
+
+ // Avatar pie menu
+ view_listener_t::addMenu(new LLObjectMute(), "Avatar.Mute");
+ view_listener_t::addMenu(new LLAvatarAddFriend(), "Avatar.AddFriend");
+ view_listener_t::addMenu(new LLAvatarAddContact(), "Avatar.AddContact");
+ commit.add("Avatar.Freeze", boost::bind(&handle_avatar_freeze, LLSD()));
+ view_listener_t::addMenu(new LLAvatarDebug(), "Avatar.Debug");
+ view_listener_t::addMenu(new LLAvatarVisibleDebug(), "Avatar.VisibleDebug");
+ view_listener_t::addMenu(new LLAvatarInviteToGroup(), "Avatar.InviteToGroup");
+ commit.add("Avatar.Eject", boost::bind(&handle_avatar_eject, LLSD()));
+ commit.add("Avatar.ShowInspector", boost::bind(&handle_avatar_show_inspector));
+ view_listener_t::addMenu(new LLAvatarSendIM(), "Avatar.SendIM");
+ view_listener_t::addMenu(new LLAvatarCall(), "Avatar.Call");
+ enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall));
+ view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse");
+
+ view_listener_t::addMenu(new LLAvatarEnableAddFriend(), "Avatar.EnableAddFriend");
+ enable.add("Avatar.EnableFreezeEject", boost::bind(&enable_freeze_eject, _2));
+
+ // Object pie menu
+ view_listener_t::addMenu(new LLObjectBuild(), "Object.Build");
+ commit.add("Object.Touch", boost::bind(&handle_object_touch));
+ commit.add("Object.SitOrStand", boost::bind(&handle_object_sit_or_stand));
+ commit.add("Object.Delete", boost::bind(&handle_object_delete));
+ view_listener_t::addMenu(new LLObjectAttachToAvatar(true), "Object.AttachToAvatar");
+ view_listener_t::addMenu(new LLObjectAttachToAvatar(false), "Object.AttachAddToAvatar");
+ view_listener_t::addMenu(new LLObjectReturn(), "Object.Return");
+ view_listener_t::addMenu(new LLObjectReportAbuse(), "Object.ReportAbuse");
+ view_listener_t::addMenu(new LLObjectMute(), "Object.Mute");
+
+ enable.add("Object.VisibleTake", boost::bind(&visible_take_object));
+ enable.add("Object.VisibleBuy", boost::bind(&visible_buy_object));
+
+ commit.add("Object.Buy", boost::bind(&handle_buy));
+ commit.add("Object.Edit", boost::bind(&handle_object_edit));
+ commit.add("Object.Inspect", boost::bind(&handle_object_inspect));
+ commit.add("Object.Open", boost::bind(&handle_object_open));
+ commit.add("Object.Take", boost::bind(&handle_take));
+ commit.add("Object.ShowInspector", boost::bind(&handle_object_show_inspector));
+ enable.add("Object.EnableOpen", boost::bind(&enable_object_open));
+ enable.add("Object.EnableTouch", boost::bind(&enable_object_touch, _1));
+ enable.add("Object.EnableDelete", boost::bind(&enable_object_delete));
+ enable.add("Object.EnableWear", boost::bind(&object_selected_and_point_valid));
+
+ enable.add("Object.EnableStandUp", boost::bind(&enable_object_stand_up));
+ enable.add("Object.EnableSit", boost::bind(&enable_object_sit, _1));
+
+ view_listener_t::addMenu(new LLObjectEnableReturn(), "Object.EnableReturn");
+ view_listener_t::addMenu(new LLObjectEnableReportAbuse(), "Object.EnableReportAbuse");
+
+ enable.add("Avatar.EnableMute", boost::bind(&enable_object_mute));
+ enable.add("Object.EnableMute", boost::bind(&enable_object_mute));
+ enable.add("Object.EnableBuy", boost::bind(&enable_buy_object));
+ commit.add("Object.ZoomIn", boost::bind(&handle_look_at_selection, "zoom"));
+
+ // Attachment pie menu
+ enable.add("Attachment.Label", boost::bind(&onEnableAttachmentLabel, _1, _2));
+ view_listener_t::addMenu(new LLAttachmentDrop(), "Attachment.Drop");
+ view_listener_t::addMenu(new LLAttachmentDetachFromPoint(), "Attachment.DetachFromPoint");
+ view_listener_t::addMenu(new LLAttachmentDetach(), "Attachment.Detach");
+ view_listener_t::addMenu(new LLAttachmentPointFilled(), "Attachment.PointFilled");
+ view_listener_t::addMenu(new LLAttachmentEnableDrop(), "Attachment.EnableDrop");
+ view_listener_t::addMenu(new LLAttachmentEnableDetach(), "Attachment.EnableDetach");
+
+ // Land pie menu
+ view_listener_t::addMenu(new LLLandBuild(), "Land.Build");
+ view_listener_t::addMenu(new LLLandSit(), "Land.Sit");
+ view_listener_t::addMenu(new LLLandBuyPass(), "Land.BuyPass");
+ view_listener_t::addMenu(new LLLandEdit(), "Land.Edit");
+
+ view_listener_t::addMenu(new LLLandEnableBuyPass(), "Land.EnableBuyPass");
+ commit.add("Land.Buy", boost::bind(&handle_buy_land));
+
+ // Generic actions
+ commit.add("ReportAbuse", boost::bind(&handle_report_abuse));
+ commit.add("BuyCurrency", boost::bind(&handle_buy_currency));
+ view_listener_t::addMenu(new LLShowHelp(), "ShowHelp");
+ view_listener_t::addMenu(new LLToggleHelp(), "ToggleHelp");
+ view_listener_t::addMenu(new LLPromptShowURL(), "PromptShowURL");
+ view_listener_t::addMenu(new LLShowAgentProfile(), "ShowAgentProfile");
+ view_listener_t::addMenu(new LLToggleAgentProfile(), "ToggleAgentProfile");
+ view_listener_t::addMenu(new LLToggleControl(), "ToggleControl");
+ view_listener_t::addMenu(new LLCheckControl(), "CheckControl");
+ view_listener_t::addMenu(new LLGoToObject(), "GoToObject");
+ commit.add("PayObject", boost::bind(&handle_give_money_dialog));
+
+ enable.add("EnablePayObject", boost::bind(&enable_pay_object));
+ enable.add("EnablePayAvatar", boost::bind(&enable_pay_avatar));
+ enable.add("EnableEdit", boost::bind(&enable_object_edit));
+ enable.add("VisibleBuild", boost::bind(&enable_object_build));
+
+ view_listener_t::addMenu(new LLFloaterVisible(), "FloaterVisible");
+ view_listener_t::addMenu(new LLShowSidetrayPanel(), "ShowSidetrayPanel");
+ view_listener_t::addMenu(new LLSidetrayPanelVisible(), "SidetrayPanelVisible");
+ view_listener_t::addMenu(new LLSomethingSelected(), "SomethingSelected");
+ view_listener_t::addMenu(new LLSomethingSelectedNoHUD(), "SomethingSelectedNoHUD");
+ view_listener_t::addMenu(new LLEditableSelected(), "EditableSelected");
+ view_listener_t::addMenu(new LLEditableSelectedMono(), "EditableSelectedMono");
+
+ view_listener_t::addMenu(new LLToggleUIHints(), "ToggleUIHints");
+
+ commit.add("Destination.show", boost::bind(&toggle_destination_and_avatar_picker, 0));
+ commit.add("Avatar.show", boost::bind(&toggle_destination_and_avatar_picker, 1));
+}
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 8b52d478e6..615e2a14ed 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1,6908 +1,6908 @@ -/** - * @file llviewermessage.cpp - * @brief Dumping ground for viewer-side message system callbacks. - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" -#include "llviewermessage.h" -#include "boost/lexical_cast.hpp" - -// Linden libraries -#include "llanimationstates.h" -#include "llaudioengine.h" -#include "llavataractions.h" -#include "llavatarnamecache.h" // IDEVO HACK -#include "lscript_byteformat.h" -#include "lleconomy.h" -#include "lleventtimer.h" -#include "llfloaterreg.h" -#include "llfollowcamparams.h" -#include "llinventorydefines.h" -#include "lllslconstants.h" -#include "llregionhandle.h" -#include "llsdserialize.h" -#include "llteleportflags.h" -#include "lltransactionflags.h" -#include "llvfile.h" -#include "llvfs.h" -#include "llxfermanager.h" -#include "mean_collision_data.h" - -#include "llagent.h" -#include "llagentcamera.h" -#include "llcallingcard.h" -#include "llbuycurrencyhtml.h" -#include "llfirstuse.h" -#include "llfloaterbuyland.h" -#include "llfloaterland.h" -#include "llfloaterregioninfo.h" -#include "llfloaterlandholdings.h" -#include "llfloaterpostcard.h" -#include "llfloaterpreference.h" -#include "llhudeffecttrail.h" -#include "llhudmanager.h" -#include "llinventoryfunctions.h" -#include "llinventoryobserver.h" -#include "llinventorypanel.h" -#include "llnearbychat.h" -#include "llnotifications.h" -#include "llnotificationsutil.h" -#include "llpanelgrouplandmoney.h" -#include "llrecentpeople.h" -#include "llscriptfloater.h" -#include "llselectmgr.h" -#include "llsidetray.h" -#include "llstartup.h" -#include "llsky.h" -#include "llslurl.h" -#include "llstatenums.h" -#include "llstatusbar.h" -#include "llimview.h" -#include "llspeakers.h" -#include "lltrans.h" -#include "lltranslate.h" -#include "llviewerfoldertype.h" -#include "llvoavatar.h" // IDEVO HACK -#include "lluri.h" -#include "llviewergenericmessage.h" -#include "llviewermenu.h" -#include "llviewerjoystick.h" -#include "llviewerobjectlist.h" -#include "llviewerparcelmgr.h" -#include "llviewerstats.h" -#include "llviewertexteditor.h" -#include "llviewerthrottle.h" -#include "llviewerwindow.h" -#include "llvlmanager.h" -#include "llvoavatarself.h" -#include "llvotextbubble.h" -#include "llworld.h" -#include "pipeline.h" -#include "llfloaterworldmap.h" -#include "llviewerdisplay.h" -#include "llkeythrottle.h" -#include "llgroupactions.h" -#include "llagentui.h" -#include "llpanelblockedlist.h" -#include "llpanelplaceprofile.h" - -#include <boost/algorithm/string/split.hpp> // -#include <boost/regex.hpp> - -#include "llnotificationmanager.h" // - -#if LL_MSVC -// disable boost::lexical_cast warning -#pragma warning (disable:4702) -#endif - -// -// Constants -// -const F32 BIRD_AUDIBLE_RADIUS = 32.0f; -const F32 SIT_DISTANCE_FROM_TARGET = 0.25f; -static const F32 LOGOUT_REPLY_TIME = 3.f; // Wait this long after LogoutReply before quitting. - -// Determine how quickly residents' scripts can issue question dialogs -// Allow bursts of up to 5 dialogs in 10 seconds. 10*2=20 seconds recovery if throttle kicks in -static const U32 LLREQUEST_PERMISSION_THROTTLE_LIMIT = 5; // requests -static const F32 LLREQUEST_PERMISSION_THROTTLE_INTERVAL = 10.0f; // seconds - -extern BOOL gDebugClicks; - -// function prototypes -bool check_offer_throttle(const std::string& from_name, bool check_only); -static void process_money_balance_reply_extended(LLMessageSystem* msg); - -//inventory offer throttle globals -LLFrameTimer gThrottleTimer; -const U32 OFFER_THROTTLE_MAX_COUNT=5; //number of items per time period -const F32 OFFER_THROTTLE_TIME=10.f; //time period in seconds - -//script permissions -const std::string SCRIPT_QUESTIONS[SCRIPT_PERMISSION_EOF] = - { - "ScriptTakeMoney", - "ActOnControlInputs", - "RemapControlInputs", - "AnimateYourAvatar", - "AttachToYourAvatar", - "ReleaseOwnership", - "LinkAndDelink", - "AddAndRemoveJoints", - "ChangePermissions", - "TrackYourCamera", - "ControlYourCamera" - }; - -const BOOL SCRIPT_QUESTION_IS_CAUTION[SCRIPT_PERMISSION_EOF] = -{ - TRUE, // ScriptTakeMoney, - FALSE, // ActOnControlInputs - FALSE, // RemapControlInputs - FALSE, // AnimateYourAvatar - FALSE, // AttachToYourAvatar - FALSE, // ReleaseOwnership, - FALSE, // LinkAndDelink, - FALSE, // AddAndRemoveJoints - FALSE, // ChangePermissions - FALSE, // TrackYourCamera, - FALSE // ControlYourCamera -}; - -bool friendship_offer_callback(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - LLMessageSystem* msg = gMessageSystem; - const LLSD& payload = notification["payload"]; - - // add friend to recent people list - LLRecentPeople::instance().add(payload["from_id"]); - - switch(option) - { - case 0: - { - // accept - LLAvatarTracker::formFriendship(payload["from_id"]); - - const LLUUID fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); - - // This will also trigger an onlinenotification if the user is online - msg->newMessageFast(_PREHASH_AcceptFriendship); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_TransactionBlock); - msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]); - msg->nextBlockFast(_PREHASH_FolderData); - msg->addUUIDFast(_PREHASH_FolderID, fid); - msg->sendReliable(LLHost(payload["sender"].asString())); - - LLSD payload = notification["payload"]; - payload["SUPPRESS_TOAST"] = true; - LLNotificationsUtil::add("FriendshipAcceptedByMe", - notification["substitutions"], payload); - break; - } - case 1: // Decline - { - LLSD payload = notification["payload"]; - payload["SUPPRESS_TOAST"] = true; - LLNotificationsUtil::add("FriendshipDeclinedByMe", - notification["substitutions"], payload); - } - // fall-through - case 2: // Send IM - decline and start IM session - { - // decline - // We no longer notify other viewers, but we DO still send - // the rejection to the simulator to delete the pending userop. - msg->newMessageFast(_PREHASH_DeclineFriendship); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_TransactionBlock); - msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]); - msg->sendReliable(LLHost(payload["sender"].asString())); - - // start IM session - if(2 == option) - { - LLAvatarActions::startIM(payload["from_id"].asUUID()); - } - } - default: - // close button probably, possibly timed out - break; - } - - return false; -} -static LLNotificationFunctorRegistration friendship_offer_callback_reg("OfferFriendship", friendship_offer_callback); -static LLNotificationFunctorRegistration friendship_offer_callback_reg_nm("OfferFriendshipNoMessage", friendship_offer_callback); - -//const char BUSY_AUTO_RESPONSE[] = "The Resident you messaged is in 'busy mode' which means they have " -// "requested not to be disturbed. Your message will still be shown in their IM " -// "panel for later viewing."; - -// -// Functions -// - -void give_money(const LLUUID& uuid, LLViewerRegion* region, S32 amount, BOOL is_group, - S32 trx_type, const std::string& desc) -{ - if(0 == amount || !region) return; - amount = abs(amount); - LL_INFOS("Messaging") << "give_money(" << uuid << "," << amount << ")"<< LL_ENDL; - if(can_afford_transaction(amount)) - { -// gStatusBar->debitBalance(amount); - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_MoneyTransferRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_MoneyData); - msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_DestID, uuid); - msg->addU8Fast(_PREHASH_Flags, pack_transaction_flags(FALSE, is_group)); - msg->addS32Fast(_PREHASH_Amount, amount); - msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY); - msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY); - msg->addS32Fast(_PREHASH_TransactionType, trx_type ); - msg->addStringFast(_PREHASH_Description, desc); - msg->sendReliable(region->getHost()); - } - else - { - LLStringUtil::format_map_t args; - args["AMOUNT"] = llformat("%d", amount); - LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("giving", args), amount ); - } -} - -void send_complete_agent_movement(const LLHost& sim_host) -{ - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_CompleteAgentMovement); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addU32Fast(_PREHASH_CircuitCode, msg->mOurCircuitCode); - msg->sendReliable(sim_host); -} - -void process_logout_reply(LLMessageSystem* msg, void**) -{ - // The server has told us it's ok to quit. - LL_DEBUGS("Messaging") << "process_logout_reply" << LL_ENDL; - - LLUUID agent_id; - msg->getUUID("AgentData", "AgentID", agent_id); - LLUUID session_id; - msg->getUUID("AgentData", "SessionID", session_id); - if((agent_id != gAgent.getID()) || (session_id != gAgent.getSessionID())) - { - LL_WARNS("Messaging") << "Bogus Logout Reply" << LL_ENDL; - } - - LLInventoryModel::update_map_t parents; - S32 count = msg->getNumberOfBlocksFast( _PREHASH_InventoryData ); - for(S32 i = 0; i < count; ++i) - { - LLUUID item_id; - msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i); - - if( (1 == count) && item_id.isNull() ) - { - // Detect dummy item. Indicates an empty list. - break; - } - - // We do not need to track the asset ids, just account for an - // updated inventory version. - LL_INFOS("Messaging") << "process_logout_reply itemID=" << item_id << LL_ENDL; - LLInventoryItem* item = gInventory.getItem( item_id ); - if( item ) - { - parents[item->getParentUUID()] = 0; - gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id); - } - else - { - LL_INFOS("Messaging") << "process_logout_reply item not found: " << item_id << LL_ENDL; - } - } - LLAppViewer::instance()->forceQuit(); -} - -void process_layer_data(LLMessageSystem *mesgsys, void **user_data) -{ - LLViewerRegion *regionp = LLWorld::getInstance()->getRegion(mesgsys->getSender()); - - if (!regionp || gNoRender) - { - return; - } - - - S32 size; - S8 type; - - mesgsys->getS8Fast(_PREHASH_LayerID, _PREHASH_Type, type); - size = mesgsys->getSizeFast(_PREHASH_LayerData, _PREHASH_Data); - if (0 == size) - { - LL_WARNS("Messaging") << "Layer data has zero size." << LL_ENDL; - return; - } - if (size < 0) - { - // getSizeFast() is probably trying to tell us about an error - LL_WARNS("Messaging") << "getSizeFast() returned negative result: " - << size - << LL_ENDL; - return; - } - U8 *datap = new U8[size]; - mesgsys->getBinaryDataFast(_PREHASH_LayerData, _PREHASH_Data, datap, size); - LLVLData *vl_datap = new LLVLData(regionp, type, datap, size); - if (mesgsys->getReceiveCompressedSize()) - { - gVLManager.addLayerData(vl_datap, mesgsys->getReceiveCompressedSize()); - } - else - { - gVLManager.addLayerData(vl_datap, mesgsys->getReceiveSize()); - } -} - -// S32 exported_object_count = 0; -// S32 exported_image_count = 0; -// S32 current_object_count = 0; -// S32 current_image_count = 0; - -// extern LLNotifyBox *gExporterNotify; -// extern LLUUID gExporterRequestID; -// extern std::string gExportDirectory; - -// extern LLUploadDialog *gExportDialog; - -// std::string gExportedFile; - -// std::map<LLUUID, std::string> gImageChecksums; - -// void export_complete() -// { -// LLUploadDialog::modalUploadFinished(); -// gExporterRequestID.setNull(); -// gExportDirectory = ""; - -// LLFILE* fXML = LLFile::fopen(gExportedFile, "rb"); /* Flawfinder: ignore */ -// fseek(fXML, 0, SEEK_END); -// long length = ftell(fXML); -// fseek(fXML, 0, SEEK_SET); -// U8 *buffer = new U8[length + 1]; -// size_t nread = fread(buffer, 1, length, fXML); -// if (nread < (size_t) length) -// { -// LL_WARNS("Messaging") << "Short read" << LL_ENDL; -// } -// buffer[nread] = '\0'; -// fclose(fXML); - -// char *pos = (char *)buffer; -// while ((pos = strstr(pos+1, "<sl:image ")) != 0) -// { -// char *pos_check = strstr(pos, "checksum=\""); - -// if (pos_check) -// { -// char *pos_uuid = strstr(pos_check, "\">"); - -// if (pos_uuid) -// { -// char image_uuid_str[UUID_STR_SIZE]; /* Flawfinder: ignore */ -// memcpy(image_uuid_str, pos_uuid+2, UUID_STR_SIZE-1); /* Flawfinder: ignore */ -// image_uuid_str[UUID_STR_SIZE-1] = 0; - -// LLUUID image_uuid(image_uuid_str); - -// LL_INFOS("Messaging") << "Found UUID: " << image_uuid << LL_ENDL; - -// std::map<LLUUID, std::string>::iterator itor = gImageChecksums.find(image_uuid); -// if (itor != gImageChecksums.end()) -// { -// LL_INFOS("Messaging") << "Replacing with checksum: " << itor->second << LL_ENDL; -// if (!itor->second.empty()) -// { -// memcpy(&pos_check[10], itor->second.c_str(), 32); /* Flawfinder: ignore */ -// } -// } -// } -// } -// } - -// LLFILE* fXMLOut = LLFile::fopen(gExportedFile, "wb"); /* Flawfinder: ignore */ -// if (fwrite(buffer, 1, length, fXMLOut) != length) -// { -// LL_WARNS("Messaging") << "Short write" << LL_ENDL; -// } -// fclose(fXMLOut); - -// delete [] buffer; -// } - - -// void exported_item_complete(const LLTSCode status, void *user_data) -// { -// //std::string *filename = (std::string *)user_data; - -// if (status < LLTS_OK) -// { -// LL_WARNS("Messaging") << "Export failed!" << LL_ENDL; -// } -// else -// { -// ++current_object_count; -// if (current_image_count == exported_image_count && current_object_count == exported_object_count) -// { -// LL_INFOS("Messaging") << "*** Export complete ***" << LL_ENDL; - -// export_complete(); -// } -// else -// { -// gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count)); -// } -// } -// } - -// struct exported_image_info -// { -// LLUUID image_id; -// std::string filename; -// U32 image_num; -// }; - -// void exported_j2c_complete(const LLTSCode status, void *user_data) -// { -// exported_image_info *info = (exported_image_info *)user_data; -// LLUUID image_id = info->image_id; -// U32 image_num = info->image_num; -// std::string filename = info->filename; -// delete info; - -// if (status < LLTS_OK) -// { -// LL_WARNS("Messaging") << "Image download failed!" << LL_ENDL; -// } -// else -// { -// LLFILE* fIn = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */ -// if (fIn) -// { -// LLPointer<LLImageJ2C> ImageUtility = new LLImageJ2C; -// LLPointer<LLImageTGA> TargaUtility = new LLImageTGA; - -// fseek(fIn, 0, SEEK_END); -// S32 length = ftell(fIn); -// fseek(fIn, 0, SEEK_SET); -// U8 *buffer = ImageUtility->allocateData(length); -// if (fread(buffer, 1, length, fIn) != length) -// { -// LL_WARNS("Messaging") << "Short read" << LL_ENDL; -// } -// fclose(fIn); -// LLFile::remove(filename); - -// // Convert to TGA -// LLPointer<LLImageRaw> image = new LLImageRaw(); - -// ImageUtility->updateData(); -// ImageUtility->decode(image, 100000.0f); - -// TargaUtility->encode(image); -// U8 *data = TargaUtility->getData(); -// S32 data_size = TargaUtility->getDataSize(); - -// std::string file_path = gDirUtilp->getDirName(filename); - -// std::string output_file = llformat("%s/image-%03d.tga", file_path.c_str(), image_num);//filename; -// //S32 name_len = output_file.length(); -// //strcpy(&output_file[name_len-3], "tga"); -// LLFILE* fOut = LLFile::fopen(output_file, "wb"); /* Flawfinder: ignore */ -// char md5_hash_string[33]; /* Flawfinder: ignore */ -// strcpy(md5_hash_string, "00000000000000000000000000000000"); /* Flawfinder: ignore */ -// if (fOut) -// { -// if (fwrite(data, 1, data_size, fOut) != data_size) -// { -// LL_WARNS("Messaging") << "Short write" << LL_ENDL; -// } -// fseek(fOut, 0, SEEK_SET); -// fclose(fOut); -// fOut = LLFile::fopen(output_file, "rb"); /* Flawfinder: ignore */ -// LLMD5 my_md5_hash(fOut); -// my_md5_hash.hex_digest(md5_hash_string); -// } - -// gImageChecksums.insert(std::pair<LLUUID, std::string>(image_id, md5_hash_string)); -// } -// } - -// ++current_image_count; -// if (current_image_count == exported_image_count && current_object_count == exported_object_count) -// { -// LL_INFOS("Messaging") << "*** Export textures complete ***" << LL_ENDL; -// export_complete(); -// } -// else -// { -// gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count)); -// } -//} - -void process_derez_ack(LLMessageSystem*, void**) -{ - if(gViewerWindow) gViewerWindow->getWindow()->decBusyCount(); -} - -void process_places_reply(LLMessageSystem* msg, void** data) -{ - LLUUID query_id; - - msg->getUUID("AgentData", "QueryID", query_id); - if (query_id.isNull()) - { - LLFloaterLandHoldings::processPlacesReply(msg, data); - } - else if(gAgent.isInGroup(query_id)) - { - LLPanelGroupLandMoney::processPlacesReply(msg, data); - } - else - { - LL_WARNS("Messaging") << "Got invalid PlacesReply message" << LL_ENDL; - } -} - -void send_sound_trigger(const LLUUID& sound_id, F32 gain) -{ - if (sound_id.isNull() || gAgent.getRegion() == NULL) - { - // disconnected agent or zero guids don't get sent (no sound) - return; - } - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_SoundTrigger); - msg->nextBlockFast(_PREHASH_SoundData); - msg->addUUIDFast(_PREHASH_SoundID, sound_id); - // Client untrusted, ids set on sim - msg->addUUIDFast(_PREHASH_OwnerID, LLUUID::null ); - msg->addUUIDFast(_PREHASH_ObjectID, LLUUID::null ); - msg->addUUIDFast(_PREHASH_ParentID, LLUUID::null ); - - msg->addU64Fast(_PREHASH_Handle, gAgent.getRegion()->getHandle()); - - LLVector3 position = gAgent.getPositionAgent(); - msg->addVector3Fast(_PREHASH_Position, position); - msg->addF32Fast(_PREHASH_Gain, gain); - - gAgent.sendMessage(); -} - -bool join_group_response(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - BOOL delete_context_data = TRUE; - bool accept_invite = false; - - LLUUID group_id = notification["payload"]["group_id"].asUUID(); - LLUUID transaction_id = notification["payload"]["transaction_id"].asUUID(); - std::string name = notification["payload"]["name"].asString(); - std::string message = notification["payload"]["message"].asString(); - S32 fee = notification["payload"]["fee"].asInteger(); - - if (option == 2 && !group_id.isNull()) - { - LLGroupActions::show(group_id); - LLSD args; - args["MESSAGE"] = message; - LLNotificationsUtil::add("JoinGroup", args, notification["payload"]); - return false; - } - if(option == 0 && !group_id.isNull()) - { - // check for promotion or demotion. - S32 max_groups = gMaxAgentGroups; - if(gAgent.isInGroup(group_id)) ++max_groups; - - if(gAgent.mGroups.count() < max_groups) - { - accept_invite = true; - } - else - { - delete_context_data = FALSE; - LLSD args; - args["NAME"] = name; - LLNotificationsUtil::add("JoinedTooManyGroupsMember", args, notification["payload"]); - } - } - - if (accept_invite) - { - // If there is a fee to join this group, make - // sure the user is sure they want to join. - if (fee > 0) - { - delete_context_data = FALSE; - LLSD args; - args["COST"] = llformat("%d", fee); - // Set the fee for next time to 0, so that we don't keep - // asking about a fee. - LLSD next_payload = notification["payload"]; - next_payload["fee"] = 0; - LLNotificationsUtil::add("JoinGroupCanAfford", - args, - next_payload); - } - else - { - send_improved_im(group_id, - std::string("name"), - std::string("message"), - IM_ONLINE, - IM_GROUP_INVITATION_ACCEPT, - transaction_id); - } - } - else - { - send_improved_im(group_id, - std::string("name"), - std::string("message"), - IM_ONLINE, - IM_GROUP_INVITATION_DECLINE, - transaction_id); - } - - return false; -} - -static void highlight_inventory_items_in_panel(const std::vector<LLUUID>& items, LLInventoryPanel *inventory_panel) -{ - if (NULL == inventory_panel) return; - - for (std::vector<LLUUID>::const_iterator item_iter = items.begin(); - item_iter != items.end(); - ++item_iter) - { - const LLUUID& item_id = (*item_iter); - if(!highlight_offered_object(item_id)) - { - continue; - } - - LLInventoryItem* item = gInventory.getItem(item_id); - llassert(item); - if (!item) { - continue; - } - - LL_DEBUGS("Inventory_Move") << "Highlighting inventory item: " << item->getName() << ", " << item_id << LL_ENDL; - LLFolderView* fv = inventory_panel->getRootFolder(); - if (fv) - { - LLFolderViewItem* fv_item = fv->getItemByID(item_id); - if (fv_item) - { - LLFolderViewItem* fv_folder = fv_item->getParentFolder(); - if (fv_folder) - { - // Parent folders can be different in case of 2 consecutive drag and drop - // operations when the second one is started before the first one completes. - LL_DEBUGS("Inventory_Move") << "Open folder: " << fv_folder->getName() << LL_ENDL; - fv_folder->setOpen(TRUE); - if (fv_folder->isSelected()) - { - fv->changeSelection(fv_folder, FALSE); - } - } - fv->changeSelection(fv_item, TRUE); - } - } - } -} - -static LLNotificationFunctorRegistration jgr_1("JoinGroup", join_group_response); -static LLNotificationFunctorRegistration jgr_2("JoinedTooManyGroupsMember", join_group_response); -static LLNotificationFunctorRegistration jgr_3("JoinGroupCanAfford", join_group_response); - - -//----------------------------------------------------------------------------- -// Instant Message -//----------------------------------------------------------------------------- -class LLOpenAgentOffer : public LLInventoryFetchItemsObserver -{ -public: - LLOpenAgentOffer(const LLUUID& object_id, - const std::string& from_name) : - LLInventoryFetchItemsObserver(object_id), - mFromName(from_name) {} - /*virtual*/ void startFetch() - { - for (uuid_vec_t::const_iterator it = mIDs.begin(); it < mIDs.end(); ++it) - { - LLViewerInventoryCategory* cat = gInventory.getCategory(*it); - if (cat) - { - mComplete.push_back((*it)); - } - } - LLInventoryFetchItemsObserver::startFetch(); - } - /*virtual*/ void done() - { - open_inventory_offer(mComplete, mFromName); - gInventory.removeObserver(this); - delete this; - } -private: - std::string mFromName; -}; - -/** - * Class to observe adding of new items moved from the world to user's inventory to select them in inventory. - * - * We can't create it each time items are moved because "drop" event is sent separately for each - * element even while multi-dragging. We have to have the only instance of the observer. See EXT-4347. - */ -class LLViewerInventoryMoveFromWorldObserver : public LLInventoryAddItemByAssetObserver -{ -public: - LLViewerInventoryMoveFromWorldObserver() - : LLInventoryAddItemByAssetObserver() - , mActivePanel(NULL) - { - - } - - void setMoveIntoFolderID(const LLUUID& into_folder_uuid) {mMoveIntoFolderID = into_folder_uuid; } - -private: - /*virtual */void onAssetAdded(const LLUUID& asset_id) - { - // Store active Inventory panel. - mActivePanel = LLInventoryPanel::getActiveInventoryPanel(); - - // Store selected items (without destination folder) - mSelectedItems.clear(); - if (mActivePanel) - { - mSelectedItems = mActivePanel->getRootFolder()->getSelectionList(); - } - mSelectedItems.erase(mMoveIntoFolderID); - } - - /** - * Selects added inventory items watched by their Asset UUIDs if selection was not changed since - * all items were started to watch (dropped into a folder). - */ - void done() - { - // if selection is not changed since watch started lets hightlight new items. - if (mActivePanel && !isSelectionChanged()) - { - LL_DEBUGS("Inventory_Move") << "Selecting new items..." << LL_ENDL; - mActivePanel->clearSelection(); - highlight_inventory_items_in_panel(mAddedItems, mActivePanel); - } - } - - /** - * Returns true if selected inventory items were changed since moved inventory items were started to watch. - */ - bool isSelectionChanged() - { - const LLInventoryPanel * const current_active_panel = LLInventoryPanel::getActiveInventoryPanel(); - - if (NULL == mActivePanel || current_active_panel != mActivePanel) - { - return true; - } - - // get selected items (without destination folder) - selected_items_t selected_items = mActivePanel->getRootFolder()->getSelectionList(); - selected_items.erase(mMoveIntoFolderID); - - // compare stored & current sets of selected items - selected_items_t different_items; - std::set_symmetric_difference(mSelectedItems.begin(), mSelectedItems.end(), - selected_items.begin(), selected_items.end(), std::inserter(different_items, different_items.begin())); - - LL_DEBUGS("Inventory_Move") << "Selected firstly: " << mSelectedItems.size() - << ", now: " << selected_items.size() << ", difference: " << different_items.size() << LL_ENDL; - - return different_items.size() > 0; - } - - LLInventoryPanel *mActivePanel; - typedef std::set<LLUUID> selected_items_t; - selected_items_t mSelectedItems; - - /** - * UUID of FolderViewFolder into which watched items are moved. - * - * Destination FolderViewFolder becomes selected while mouse hovering (when dragged items are dropped). - * - * If mouse is moved out it set unselected and number of selected items is changed - * even if selected items in Inventory stay the same. - * So, it is used to update stored selection list. - * - * @see onAssetAdded() - * @see isSelectionChanged() - */ - LLUUID mMoveIntoFolderID; -}; - -LLViewerInventoryMoveFromWorldObserver* gInventoryMoveObserver = NULL; - -void set_dad_inventory_item(LLInventoryItem* inv_item, const LLUUID& into_folder_uuid) -{ - start_new_inventory_observer(); - - gInventoryMoveObserver->setMoveIntoFolderID(into_folder_uuid); - gInventoryMoveObserver->watchAsset(inv_item->getAssetUUID()); -} - -//unlike the FetchObserver for AgentOffer, we only make one -//instance of the AddedObserver for TaskOffers -//and it never dies. We do this because we don't know the UUID of -//task offers until they are accepted, so we don't wouldn't -//know what to watch for, so instead we just watch for all additions. -class LLOpenTaskOffer : public LLInventoryAddedObserver -{ -protected: - /*virtual*/ void done() - { - for (uuid_vec_t::iterator it = mAdded.begin(); it != mAdded.end();) - { - const LLUUID& item_uuid = *it; - bool was_moved = false; - LLInventoryObject* added_object = gInventory.getObject(item_uuid); - if (added_object) - { - // cast to item to get Asset UUID - LLInventoryItem* added_item = dynamic_cast<LLInventoryItem*>(added_object); - if (added_item) - { - const LLUUID& asset_uuid = added_item->getAssetUUID(); - if (gInventoryMoveObserver->isAssetWatched(asset_uuid)) - { - LL_DEBUGS("Inventory_Move") << "Found asset UUID: " << asset_uuid << LL_ENDL; - was_moved = true; - } - } - } - - if (was_moved) - { - it = mAdded.erase(it); - } - else ++it; - } - - open_inventory_offer(mAdded, ""); - mAdded.clear(); - } - }; - -class LLOpenTaskGroupOffer : public LLInventoryAddedObserver -{ -protected: - /*virtual*/ void done() - { - open_inventory_offer(mAdded, "group_offer"); - mAdded.clear(); - gInventory.removeObserver(this); - delete this; - } -}; - -//one global instance to bind them -LLOpenTaskOffer* gNewInventoryObserver=NULL; - -class LLNewInventoryHintObserver : public LLInventoryAddedObserver -{ -protected: - /*virtual*/ void done() - { - LLFirstUse::newInventory(); - } -}; - -void start_new_inventory_observer() -{ - if (!gNewInventoryObserver) //task offer observer - { - // Observer is deleted by gInventory - gNewInventoryObserver = new LLOpenTaskOffer; - gInventory.addObserver(gNewInventoryObserver); - } - - if (!gInventoryMoveObserver) //inventory move from the world observer - { - // Observer is deleted by gInventory - gInventoryMoveObserver = new LLViewerInventoryMoveFromWorldObserver; - gInventory.addObserver(gInventoryMoveObserver); - } - - gInventory.addObserver(new LLNewInventoryHintObserver()); -} - -class LLDiscardAgentOffer : public LLInventoryFetchItemsObserver -{ - LOG_CLASS(LLDiscardAgentOffer); -public: - LLDiscardAgentOffer(const LLUUID& folder_id, const LLUUID& object_id) : - LLInventoryFetchItemsObserver(object_id), - mFolderID(folder_id), - mObjectID(object_id) {} - virtual ~LLDiscardAgentOffer() {} - virtual void done() - { - LL_DEBUGS("Messaging") << "LLDiscardAgentOffer::done()" << LL_ENDL; - const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - bool notify = false; - if(trash_id.notNull() && mObjectID.notNull()) - { - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(mFolderID, -1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(trash_id, 1); - update.push_back(new_folder); - gInventory.accountForUpdate(update); - gInventory.moveObject(mObjectID, trash_id); - LLInventoryObject* obj = gInventory.getObject(mObjectID); - if(obj) - { - // no need to restamp since this is already a freshly - // stamped item. - obj->updateParentOnServer(FALSE); - notify = true; - } - } - else - { - LL_WARNS("Messaging") << "DiscardAgentOffer unable to find: " - << (trash_id.isNull() ? "trash " : "") - << (mObjectID.isNull() ? "object" : "") << LL_ENDL; - } - gInventory.removeObserver(this); - if(notify) - { - gInventory.notifyObservers(); - } - delete this; - } -protected: - LLUUID mFolderID; - LLUUID mObjectID; -}; - - -//Returns TRUE if we are OK, FALSE if we are throttled -//Set check_only true if you want to know the throttle status -//without registering a hit -bool check_offer_throttle(const std::string& from_name, bool check_only) -{ - static U32 throttle_count; - static bool throttle_logged; - LLChat chat; - std::string log_message; - - if (!gSavedSettings.getBOOL("ShowNewInventory")) - return false; - - if (check_only) - { - return gThrottleTimer.hasExpired(); - } - - if(gThrottleTimer.checkExpirationAndReset(OFFER_THROTTLE_TIME)) - { - LL_DEBUGS("Messaging") << "Throttle Expired" << LL_ENDL; - throttle_count=1; - throttle_logged=false; - return true; - } - else //has not expired - { - LL_DEBUGS("Messaging") << "Throttle Not Expired, Count: " << throttle_count << LL_ENDL; - // When downloading the initial inventory we get a lot of new items - // coming in and can't tell that from spam. - if (LLStartUp::getStartupState() >= STATE_STARTED - && throttle_count >= OFFER_THROTTLE_MAX_COUNT) - { - if (!throttle_logged) - { - // Use the name of the last item giver, who is probably the person - // spamming you. - - LLStringUtil::format_map_t arg; - std::string log_msg; - std::ostringstream time ; - time<<OFFER_THROTTLE_TIME; - - arg["APP_NAME"] = LLAppViewer::instance()->getSecondLifeTitle(); - arg["TIME"] = time.str(); - - if (!from_name.empty()) - { - arg["FROM_NAME"] = from_name; - log_msg = LLTrans::getString("ItemsComingInTooFastFrom", arg); - } - else - { - log_msg = LLTrans::getString("ItemsComingInTooFast", arg); - } - - //this is kinda important, so actually put it on screen - LLSD args; - args["MESSAGE"] = log_msg; - LLNotificationsUtil::add("SystemMessage", args); - - throttle_logged=true; - } - return false; - } - else - { - throttle_count++; - return true; - } - } -} - -void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_name) -{ - for (uuid_vec_t::const_iterator obj_iter = objects.begin(); - obj_iter != objects.end(); - ++obj_iter) - { - const LLUUID& obj_id = (*obj_iter); - if(!highlight_offered_object(obj_id)) - { - continue; - } - - const LLInventoryObject *obj = gInventory.getObject(obj_id); - if (!obj) - { - llwarns << "Cannot find object [ itemID:" << obj_id << " ] to open." << llendl; - continue; - } - - const LLAssetType::EType asset_type = obj->getActualType(); - - // Either an inventory item or a category. - const LLInventoryItem* item = dynamic_cast<const LLInventoryItem*>(obj); - if (item) - { - //////////////////////////////////////////////////////////////////////////////// - // Special handling for various types. - if (check_offer_throttle(from_name, false)) // If we are throttled, don't display - { - LL_DEBUGS("Messaging") << "Highlighting inventory item: " << item->getUUID() << LL_ENDL; - // If we opened this ourselves, focus it - const BOOL take_focus = from_name.empty() ? TAKE_FOCUS_YES : TAKE_FOCUS_NO; - switch(asset_type) - { - case LLAssetType::AT_NOTECARD: - { - LLFloaterReg::showInstance("preview_notecard", LLSD(obj_id), take_focus); - break; - } - case LLAssetType::AT_LANDMARK: - { - LLInventoryCategory* parent_folder = gInventory.getCategory(item->getParentUUID()); - if ("inventory_handler" == from_name) - { - //we have to filter inventory_handler messages to avoid notification displaying - LLSideTray::getInstance()->showPanel("panel_places", - LLSD().with("type", "landmark").with("id", item->getUUID())); - } - else if("group_offer" == from_name) - { - // "group_offer" is passed by LLOpenTaskGroupOffer - // Notification about added landmark will be generated under the "from_name.empty()" called from LLOpenTaskOffer::done(). - LLSD args; - args["type"] = "landmark"; - args["id"] = obj_id; - LLSideTray::getInstance()->showPanel("panel_places", args); - - continue; - } - else if(from_name.empty()) - { - std::string folder_name; - if (parent_folder) - { - // Localize folder name. - // *TODO: share this code? - folder_name = parent_folder->getName(); - if (LLFolderType::lookupIsProtectedType(parent_folder->getPreferredType())) - { - LLTrans::findString(folder_name, "InvFolder " + folder_name); - } - } - else - { - folder_name = LLTrans::getString("Unknown"); - } - - // we receive a message from LLOpenTaskOffer, it mean that new landmark has been added. - LLSD args; - args["LANDMARK_NAME"] = item->getName(); - args["FOLDER_NAME"] = folder_name; - LLNotificationsUtil::add("LandmarkCreated", args); - } - } - break; - case LLAssetType::AT_TEXTURE: - { - LLFloaterReg::showInstance("preview_texture", LLSD(obj_id), take_focus); - break; - } - case LLAssetType::AT_ANIMATION: - LLFloaterReg::showInstance("preview_anim", LLSD(obj_id), take_focus); - break; - case LLAssetType::AT_SCRIPT: - LLFloaterReg::showInstance("preview_script", LLSD(obj_id), take_focus); - break; - case LLAssetType::AT_SOUND: - LLFloaterReg::showInstance("preview_sound", LLSD(obj_id), take_focus); - break; - default: - break; - } - } - } - - //////////////////////////////////////////////////////////////////////////////// - // Highlight item - const BOOL auto_open = - gSavedSettings.getBOOL("ShowInInventory") && // don't open if showininventory is false - !from_name.empty(); // don't open if it's not from anyone. - LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(auto_open); - if(active_panel) - { - LL_DEBUGS("Messaging") << "Highlighting" << obj_id << LL_ENDL; - LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus(); - active_panel->setSelection(obj_id, TAKE_FOCUS_NO); - gFocusMgr.setKeyboardFocus(focus_ctrl); - } - } -} - -bool highlight_offered_object(const LLUUID& obj_id) -{ - const LLInventoryObject* obj = gInventory.getObject(obj_id); - if(!obj) - { - LL_WARNS("Messaging") << "Unable to show inventory item: " << obj_id << LL_ENDL; - return false; - } - - //////////////////////////////////////////////////////////////////////////////// - // Don't highlight if it's in certain "quiet" folders which don't need UI - // notification (e.g. trash, cof, lost-and-found). - if(!gAgent.getAFK()) - { - const LLViewerInventoryCategory *parent = gInventory.getFirstNondefaultParent(obj_id); - if (parent) - { - const LLFolderType::EType parent_type = parent->getPreferredType(); - if (LLViewerFolderType::lookupIsQuietType(parent_type)) - { - return false; - } - } - } - - return true; -} - -void inventory_offer_mute_callback(const LLUUID& blocked_id, - const std::string& full_name, - bool is_group, - boost::shared_ptr<LLNotificationResponderInterface> offer_ptr) -{ - LLOfferInfo* offer = dynamic_cast<LLOfferInfo*>(offer_ptr.get()); - - std::string from_name = full_name; - LLMute::EType type; - if (is_group) - { - type = LLMute::GROUP; - } - else if(offer && offer->mFromObject) - { - //we have to block object by name because blocked_id is an id of owner - type = LLMute::BY_NAME; - } - else - { - type = LLMute::AGENT; - } - - // id should be null for BY_NAME mute, see LLMuteList::add for details - LLMute mute(type == LLMute::BY_NAME ? LLUUID::null : blocked_id, from_name, type); - if (LLMuteList::getInstance()->add(mute)) - { - LLPanelBlockedList::showPanelAndSelect(blocked_id); - } - - // purge the message queue of any previously queued inventory offers from the same source. - class OfferMatcher : public LLNotificationsUI::LLScreenChannel::Matcher - { - public: - OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {} - bool matches(const LLNotificationPtr notification) const - { - if(notification->getName() == "ObjectGiveItem" - || notification->getName() == "UserGiveItem") - { - return (notification->getPayload()["from_id"].asUUID() == blocked_id); - } - return FALSE; - } - private: - const LLUUID& blocked_id; - }; - - LLNotificationsUI::LLChannelManager::getInstance()->killToastsFromChannel(LLUUID( - gSavedSettings.getString("NotificationChannelUUID")), OfferMatcher(blocked_id)); -} - -LLOfferInfo::LLOfferInfo() - : LLNotificationResponderInterface() - , mFromGroup(FALSE) - , mFromObject(FALSE) - , mIM(IM_NOTHING_SPECIAL) - , mType(LLAssetType::AT_NONE) - , mPersist(false) -{ -} - -LLOfferInfo::LLOfferInfo(const LLSD& sd) -{ - mIM = (EInstantMessage)sd["im_type"].asInteger(); - mFromID = sd["from_id"].asUUID(); - mFromGroup = sd["from_group"].asBoolean(); - mFromObject = sd["from_object"].asBoolean(); - mTransactionID = sd["transaction_id"].asUUID(); - mFolderID = sd["folder_id"].asUUID(); - mObjectID = sd["object_id"].asUUID(); - mType = LLAssetType::lookup(sd["type"].asString().c_str()); - mFromName = sd["from_name"].asString(); - mDesc = sd["description"].asString(); - mHost = LLHost(sd["sender"].asString()); - mPersist = sd["persist"].asBoolean(); -} - -LLOfferInfo::LLOfferInfo(const LLOfferInfo& info) -{ - mIM = info.mIM; - mFromID = info.mFromID; - mFromGroup = info.mFromGroup; - mFromObject = info.mFromObject; - mTransactionID = info.mTransactionID; - mFolderID = info.mFolderID; - mObjectID = info.mObjectID; - mType = info.mType; - mFromName = info.mFromName; - mDesc = info.mDesc; - mHost = info.mHost; - mPersist = info.mPersist; -} - -LLSD LLOfferInfo::asLLSD() -{ - LLSD sd; - sd["im_type"] = mIM; - sd["from_id"] = mFromID; - sd["from_group"] = mFromGroup; - sd["from_object"] = mFromObject; - sd["transaction_id"] = mTransactionID; - sd["folder_id"] = mFolderID; - sd["object_id"] = mObjectID; - sd["type"] = LLAssetType::lookup(mType); - sd["from_name"] = mFromName; - sd["description"] = mDesc; - sd["sender"] = mHost.getIPandPort(); - sd["persist"] = mPersist; - return sd; -} - -void LLOfferInfo::fromLLSD(const LLSD& params) -{ - *this = params; -} - -void LLOfferInfo::send_auto_receive_response(void) -{ - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_ImprovedInstantMessage); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_MessageBlock); - msg->addBOOLFast(_PREHASH_FromGroup, FALSE); - msg->addUUIDFast(_PREHASH_ToAgentID, mFromID); - msg->addU8Fast(_PREHASH_Offline, IM_ONLINE); - msg->addUUIDFast(_PREHASH_ID, mTransactionID); - msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary - std::string name; - LLAgentUI::buildFullname(name); - msg->addStringFast(_PREHASH_FromAgentName, name); - msg->addStringFast(_PREHASH_Message, ""); - msg->addU32Fast(_PREHASH_ParentEstateID, 0); - msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null); - msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent()); - - // Auto Receive Message. The math for the dialog works, because the accept - // for inventory_offered, task_inventory_offer or - // group_notice_inventory is 1 greater than the offer integer value. - // Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED, - // or IM_GROUP_NOTICE_INVENTORY_ACCEPTED - msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1)); - msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(mFolderID.mData), - sizeof(mFolderID.mData)); - // send the message - msg->sendReliable(mHost); - - if(IM_INVENTORY_OFFERED == mIM) - { - // add buddy to recent people list - LLRecentPeople::instance().add(mFromID); - } -} - -void LLOfferInfo::handleRespond(const LLSD& notification, const LLSD& response) -{ - initRespondFunctionMap(); - - const std::string name = notification["name"].asString(); - if(mRespondFunctions.find(name) == mRespondFunctions.end()) - { - llwarns << "Unexpected notification name : " << name << llendl; - llassert(!"Unexpected notification name"); - return; - } - - mRespondFunctions[name](notification, response); -} - -bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& response) -{ - LLChat chat; - std::string log_message; - S32 button = LLNotificationsUtil::getSelectedOption(notification, response); - - LLInventoryObserver* opener = NULL; - LLViewerInventoryCategory* catp = NULL; - catp = (LLViewerInventoryCategory*)gInventory.getCategory(mObjectID); - LLViewerInventoryItem* itemp = NULL; - if(!catp) - { - itemp = (LLViewerInventoryItem*)gInventory.getItem(mObjectID); - } - - // For muting, we need to add the mute, then decline the offer. - // This must be done here because: - // * callback may be called immediately, - // * adding the mute sends a message, - // * we can't build two messages at once. - if (2 == button) // Block - { - LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID()); - - llassert(notification_ptr != NULL); - if (notification_ptr != NULL) - { - gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback,_1,_2,_3,notification_ptr->getResponderPtr())); - } - } - - std::string from_string; // Used in the pop-up. - std::string chatHistory_string; // Used in chat history. - - // TODO: when task inventory offers can also be handled the new way, migrate the code that sets these strings here: - from_string = chatHistory_string = mFromName; - - bool busy=FALSE; - - switch(button) - { - case IOR_SHOW: - // we will want to open this item when it comes back. - LL_DEBUGS("Messaging") << "Initializing an opener for tid: " << mTransactionID - << LL_ENDL; - switch (mIM) - { - case IM_INVENTORY_OFFERED: - { - // This is an offer from an agent. In this case, the back - // end has already copied the items into your inventory, - // so we can fetch it out of our inventory. - if (gSavedSettings.getBOOL("ShowOfferedInventory")) - { - LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(mObjectID, from_string); - open_agent_offer->startFetch(); - if(catp || (itemp && itemp->isFinished())) - { - open_agent_offer->done(); - } - else - { - opener = open_agent_offer; - } - } - } - break; - case IM_GROUP_NOTICE: - opener = new LLOpenTaskGroupOffer; - send_auto_receive_response(); - break; - case IM_TASK_INVENTORY_OFFERED: - case IM_GROUP_NOTICE_REQUESTED: - // This is an offer from a task or group. - // We don't use a new instance of an opener - // We instead use the singular observer gOpenTaskOffer - // Since it already exists, we don't need to actually do anything - break; - default: - LL_WARNS("Messaging") << "inventory_offer_callback: unknown offer type" << LL_ENDL; - break; - } - break; - // end switch (mIM) - - case IOR_ACCEPT: - //don't spam them if they are getting flooded - if (check_offer_throttle(mFromName, true)) - { - log_message = chatHistory_string + " " + LLTrans::getString("InvOfferGaveYou") + " " + mDesc + LLTrans::getString("."); - LLSD args; - args["MESSAGE"] = log_message; - LLNotificationsUtil::add("SystemMessage", args); - } - break; - - case IOR_BUSY: - //Busy falls through to decline. Says to make busy message. - busy=TRUE; - case IOR_MUTE: - // MUTE falls through to decline - case IOR_DECLINE: - { - { - LLStringUtil::format_map_t log_message_args; - log_message_args["DESC"] = mDesc; - log_message_args["NAME"] = mFromName; - log_message = LLTrans::getString("InvOfferDecline", log_message_args); - } - chat.mText = log_message; - if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::getInstance()->isLinden(mFromName) ) // muting for SL-42269 - { - chat.mMuted = TRUE; - } - - // *NOTE dzaporozhan - // Disabled logging to old chat floater to fix crash in group notices - EXT-4149 - // LLFloaterChat::addChatHistory(chat); - - LLDiscardAgentOffer* discard_agent_offer = new LLDiscardAgentOffer(mFolderID, mObjectID); - discard_agent_offer->startFetch(); - if (catp || (itemp && itemp->isFinished())) - { - discard_agent_offer->done(); - } - else - { - opener = discard_agent_offer; - } - - - if (busy && (!mFromGroup && !mFromObject)) - { - busy_message(gMessageSystem, mFromID); - } - break; - } - default: - // close button probably - // The item has already been fetched and is in your inventory, we simply won't highlight it - // OR delete it if the notification gets killed, since we don't want that to be a vector for - // losing inventory offers. - break; - } - - if(opener) - { - gInventory.addObserver(opener); - } - - if(!mPersist) - { - delete this; - } - return false; -} - -bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const LLSD& response) -{ - LLChat chat; - std::string log_message; - S32 button = LLNotification::getSelectedOption(notification, response); - - // For muting, we need to add the mute, then decline the offer. - // This must be done here because: - // * callback may be called immediately, - // * adding the mute sends a message, - // * we can't build two messages at once. - if (2 == button) - { - LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID()); - - llassert(notification_ptr != NULL); - if (notification_ptr != NULL) - { - gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback,_1,_2,_3,notification_ptr->getResponderPtr())); - } - } - - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_ImprovedInstantMessage); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_MessageBlock); - msg->addBOOLFast(_PREHASH_FromGroup, FALSE); - msg->addUUIDFast(_PREHASH_ToAgentID, mFromID); - msg->addU8Fast(_PREHASH_Offline, IM_ONLINE); - msg->addUUIDFast(_PREHASH_ID, mTransactionID); - msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary - std::string name; - LLAgentUI::buildFullname(name); - msg->addStringFast(_PREHASH_FromAgentName, name); - msg->addStringFast(_PREHASH_Message, ""); - msg->addU32Fast(_PREHASH_ParentEstateID, 0); - msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null); - msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent()); - LLInventoryObserver* opener = NULL; - - std::string from_string; // Used in the pop-up. - std::string chatHistory_string; // Used in chat history. - if (mFromObject == TRUE) - { - if (mFromGroup) - { - std::string group_name; - if (gCacheName->getGroupName(mFromID, group_name)) - { - from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+"'" - + mFromName + LLTrans::getString("'") +" " + LLTrans::getString("InvOfferOwnedByGroup") - + " "+ "'" + group_name + "'"; - - chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByGroup") - + " " + group_name + "'"; - } - else - { - from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+"'" - + mFromName +"'"+ " " + LLTrans::getString("InvOfferOwnedByUnknownGroup"); - chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownGroup"); - } - } - else - { - std::string full_name; - if (gCacheName->getFullName(mFromID, full_name)) - { - from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+ LLTrans::getString("'") + mFromName - + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + full_name; - chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + full_name; - } - else - { - from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+LLTrans::getString("'") - + mFromName + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedByUnknownUser"); - chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownUser"); - } - } - } - else - { - from_string = chatHistory_string = mFromName; - } - - bool busy=FALSE; - - switch(button) - { - case IOR_ACCEPT: - // ACCEPT. The math for the dialog works, because the accept - // for inventory_offered, task_inventory_offer or - // group_notice_inventory is 1 greater than the offer integer value. - // Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED, - // or IM_GROUP_NOTICE_INVENTORY_ACCEPTED - msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1)); - msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(mFolderID.mData), - sizeof(mFolderID.mData)); - // send the message - msg->sendReliable(mHost); - - //don't spam them if they are getting flooded - if (check_offer_throttle(mFromName, true)) - { - log_message = chatHistory_string + " " + LLTrans::getString("InvOfferGaveYou") + " " + mDesc + LLTrans::getString("."); - LLSD args; - args["MESSAGE"] = log_message; - LLNotificationsUtil::add("SystemMessage", args); - } - - // we will want to open this item when it comes back. - LL_DEBUGS("Messaging") << "Initializing an opener for tid: " << mTransactionID - << LL_ENDL; - switch (mIM) - { - case IM_TASK_INVENTORY_OFFERED: - case IM_GROUP_NOTICE: - case IM_GROUP_NOTICE_REQUESTED: - { - // This is an offer from a task or group. - // We don't use a new instance of an opener - // We instead use the singular observer gOpenTaskOffer - // Since it already exists, we don't need to actually do anything - } - break; - default: - LL_WARNS("Messaging") << "inventory_offer_callback: unknown offer type" << LL_ENDL; - break; - } // end switch (mIM) - break; - - case IOR_BUSY: - //Busy falls through to decline. Says to make busy message. - busy=TRUE; - case IOR_MUTE: - // MUTE falls through to decline - case IOR_DECLINE: - // DECLINE. The math for the dialog works, because the decline - // for inventory_offered, task_inventory_offer or - // group_notice_inventory is 2 greater than the offer integer value. - // Generates IM_INVENTORY_DECLINED, IM_TASK_INVENTORY_DECLINED, - // or IM_GROUP_NOTICE_INVENTORY_DECLINED - default: - // close button probably (or any of the fall-throughs from above) - msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 2)); - msg->addBinaryDataFast(_PREHASH_BinaryBucket, EMPTY_BINARY_BUCKET, EMPTY_BINARY_BUCKET_SIZE); - // send the message - msg->sendReliable(mHost); - - if (gSavedSettings.getBOOL("LogInventoryDecline")) - { - LLStringUtil::format_map_t log_message_args; - log_message_args["DESC"] = mDesc; - log_message_args["NAME"] = mFromName; - log_message = LLTrans::getString("InvOfferDecline", log_message_args); - - LLSD args; - args["MESSAGE"] = log_message; - LLNotificationsUtil::add("SystemMessage", args); - } - - if (busy && (!mFromGroup && !mFromObject)) - { - busy_message(msg,mFromID); - } - break; - } - - if(opener) - { - gInventory.addObserver(opener); - } - - if(!mPersist) - { - delete this; - } - return false; -} - -class LLPostponedOfferNotification: public LLPostponedNotification -{ -protected: - /* virtual */ - void modifyNotificationParams() - { - LLSD substitutions = mParams.substitutions; - substitutions["NAME"] = mName; - mParams.substitutions = substitutions; - } -}; - -void LLOfferInfo::initRespondFunctionMap() -{ - if(mRespondFunctions.empty()) - { - mRespondFunctions["ObjectGiveItem"] = boost::bind(&LLOfferInfo::inventory_task_offer_callback, this, _1, _2); - mRespondFunctions["UserGiveItem"] = boost::bind(&LLOfferInfo::inventory_offer_callback, this, _1, _2); - } -} - -void inventory_offer_handler(LLOfferInfo* info) -{ - //Until throttling is implmented, busy mode should reject inventory instead of silently - //accepting it. SEE SL-39554 - if (gAgent.getBusy()) - { - info->forceResponse(IOR_BUSY); - return; - } - - //If muted, don't even go through the messaging stuff. Just curtail the offer here. - if (LLMuteList::getInstance()->isMuted(info->mFromID, info->mFromName)) - { - info->forceResponse(IOR_MUTE); - return; - } - - // Avoid the Accept/Discard dialog if the user so desires. JC - if (gSavedSettings.getBOOL("AutoAcceptNewInventory") - && (info->mType == LLAssetType::AT_NOTECARD - || info->mType == LLAssetType::AT_LANDMARK - || info->mType == LLAssetType::AT_TEXTURE)) - { - // For certain types, just accept the items into the inventory, - // and possibly open them on receipt depending upon "ShowNewInventory". - info->forceResponse(IOR_ACCEPT); - return; - } - - // Strip any SLURL from the message display. (DEV-2754) - std::string msg = info->mDesc; - int indx = msg.find(" ( http://slurl.com/secondlife/"); - if(indx == std::string::npos) - { - // try to find new slurl host - indx = msg.find(" ( http://maps.secondlife.com/secondlife/"); - } - if(indx >= 0) - { - LLStringUtil::truncate(msg, indx); - } - - LLSD args; - args["[OBJECTNAME]"] = msg; - - LLSD payload; - - // must protect against a NULL return from lookupHumanReadable() - std::string typestr = ll_safe_string(LLAssetType::lookupHumanReadable(info->mType)); - if (!typestr.empty()) - { - // human readable matches string name from strings.xml - // lets get asset type localized name - args["OBJECTTYPE"] = LLTrans::getString(typestr); - } - else - { - LL_WARNS("Messaging") << "LLAssetType::lookupHumanReadable() returned NULL - probably bad asset type: " << info->mType << LL_ENDL; - args["OBJECTTYPE"] = ""; - - // This seems safest, rather than propagating bogosity - LL_WARNS("Messaging") << "Forcing an inventory-decline for probably-bad asset type." << LL_ENDL; - info->forceResponse(IOR_DECLINE); - return; - } - - // If mObjectID is null then generate the object_id based on msg to prevent - // multiple creation of chiclets for same object. - LLUUID object_id = info->mObjectID; - if (object_id.isNull()) - object_id.generate(msg); - - payload["from_id"] = info->mFromID; - // Needed by LLScriptFloaterManager to bind original notification with - // faked for toast one. - payload["object_id"] = object_id; - // Flag indicating that this notification is faked for toast. - payload["give_inventory_notification"] = FALSE; - args["OBJECTFROMNAME"] = info->mFromName; - args["NAME"] = info->mFromName; - if (info->mFromGroup) - { - args["NAME_SLURL"] = LLSLURL("group", info->mFromID, "about").getSLURLString(); - } - else - { - args["NAME_SLURL"] = LLSLURL("agent", info->mFromID, "about").getSLURLString(); - } - std::string verb = "select?name=" + LLURI::escape(msg); - args["ITEM_SLURL"] = LLSLURL("inventory", info->mObjectID, verb.c_str()).getSLURLString(); - - LLNotification::Params p("ObjectGiveItem"); - - // Object -> Agent Inventory Offer - if (info->mFromObject) - { - // Inventory Slurls don't currently work for non agent transfers, so only display the object name. - args["ITEM_SLURL"] = msg; - // Note: sets inventory_task_offer_callback as the callback - p.substitutions(args).payload(payload).functor.responder(LLNotificationResponderPtr(info)); - info->mPersist = true; - p.name = "ObjectGiveItem"; - // Pop up inv offer chiclet and let the user accept (keep), or reject (and silently delete) the inventory. - LLPostponedNotification::add<LLPostponedOfferNotification>(p, info->mFromID, info->mFromGroup == TRUE); - } - else // Agent -> Agent Inventory Offer - { - p.responder = info; - // Note: sets inventory_offer_callback as the callback - // *TODO fix memory leak - // inventory_offer_callback() is not invoked if user received notification and - // closes viewer(without responding the notification) - p.substitutions(args).payload(payload).functor.responder(LLNotificationResponderPtr(info)); - info->mPersist = true; - p.name = "UserGiveItem"; - - // Prefetch the item into your local inventory. - LLInventoryFetchItemsObserver* fetch_item = new LLInventoryFetchItemsObserver(info->mObjectID); - fetch_item->startFetch(); - if(fetch_item->isFinished()) - { - fetch_item->done(); - } - else - { - gInventory.addObserver(fetch_item); - } - - // In viewer 2 we're now auto receiving inventory offers and messaging as such (not sending reject messages). - info->send_auto_receive_response(); - - // Inform user that there is a script floater via toast system - { - payload["give_inventory_notification"] = TRUE; - p.payload = payload; - LLPostponedNotification::add<LLPostponedOfferNotification>(p, info->mFromID, false); - } - } - - LLFirstUse::newInventory(); -} - -bool lure_callback(const LLSD& notification, const LLSD& response) -{ - S32 option = 0; - if (response.isInteger()) - { - option = response.asInteger(); - } - else - { - option = LLNotificationsUtil::getSelectedOption(notification, response); - } - - LLUUID from_id = notification["payload"]["from_id"].asUUID(); - LLUUID lure_id = notification["payload"]["lure_id"].asUUID(); - BOOL godlike = notification["payload"]["godlike"].asBoolean(); - - switch(option) - { - case 0: - { - // accept - gAgent.teleportViaLure(lure_id, godlike); - } - break; - case 1: - default: - // decline - send_simple_im(from_id, - LLStringUtil::null, - IM_LURE_DECLINED, - lure_id); - break; - } - return false; -} -static LLNotificationFunctorRegistration lure_callback_reg("TeleportOffered", lure_callback); - -bool goto_url_callback(const LLSD& notification, const LLSD& response) -{ - std::string url = notification["payload"]["url"].asString(); - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if(1 == option) - { - LLWeb::loadURL(url); - } - return false; -} -static LLNotificationFunctorRegistration goto_url_callback_reg("GotoURL", goto_url_callback); - -bool inspect_remote_object_callback(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (0 == option) - { - LLFloaterReg::showInstance("inspect_remote_object", notification["payload"]); - } - return false; -} -static LLNotificationFunctorRegistration inspect_remote_object_callback_reg("ServerObjectMessage", inspect_remote_object_callback); - -class LLPostponedServerObjectNotification: public LLPostponedNotification -{ -protected: - /* virtual */ - void modifyNotificationParams() - { - LLSD payload = mParams.payload; - mParams.payload = payload; - } -}; - -static bool parse_lure_bucket(const std::string& bucket, - U64& region_handle, - LLVector3& pos, - LLVector3& look_at, - U8& region_access) -{ - // tokenize the bucket - typedef boost::tokenizer<boost::char_separator<char> > tokenizer; - boost::char_separator<char> sep("|", "", boost::keep_empty_tokens); - tokenizer tokens(bucket, sep); - tokenizer::iterator iter = tokens.begin(); - - S32 gx,gy,rx,ry,rz,lx,ly,lz; - try - { - gx = boost::lexical_cast<S32>((*(iter)).c_str()); - gy = boost::lexical_cast<S32>((*(++iter)).c_str()); - rx = boost::lexical_cast<S32>((*(++iter)).c_str()); - ry = boost::lexical_cast<S32>((*(++iter)).c_str()); - rz = boost::lexical_cast<S32>((*(++iter)).c_str()); - lx = boost::lexical_cast<S32>((*(++iter)).c_str()); - ly = boost::lexical_cast<S32>((*(++iter)).c_str()); - lz = boost::lexical_cast<S32>((*(++iter)).c_str()); - } - catch( boost::bad_lexical_cast& ) - { - LL_WARNS("parse_lure_bucket") - << "Couldn't parse lure bucket." - << LL_ENDL; - return false; - } - // Grab region access - region_access = SIM_ACCESS_MIN; - if (++iter != tokens.end()) - { - std::string access_str((*iter).c_str()); - LLStringUtil::trim(access_str); - if ( access_str == "A" ) - { - region_access = SIM_ACCESS_ADULT; - } - else if ( access_str == "M" ) - { - region_access = SIM_ACCESS_MATURE; - } - else if ( access_str == "PG" ) - { - region_access = SIM_ACCESS_PG; - } - } - - pos.setVec((F32)rx, (F32)ry, (F32)rz); - look_at.setVec((F32)lx, (F32)ly, (F32)lz); - - region_handle = to_region_handle(gx, gy); - return true; -} - -// Strip out "Resident" for display, but only if the message came from a user -// (rather than a script) -static std::string clean_name_from_im(const std::string& name, EInstantMessage type) -{ - switch(type) - { - case IM_NOTHING_SPECIAL: - case IM_MESSAGEBOX: - case IM_GROUP_INVITATION: - case IM_INVENTORY_OFFERED: - case IM_INVENTORY_ACCEPTED: - case IM_INVENTORY_DECLINED: - case IM_GROUP_VOTE: - case IM_GROUP_MESSAGE_DEPRECATED: - //IM_TASK_INVENTORY_OFFERED - //IM_TASK_INVENTORY_ACCEPTED - //IM_TASK_INVENTORY_DECLINED - case IM_NEW_USER_DEFAULT: - case IM_SESSION_INVITE: - case IM_SESSION_P2P_INVITE: - case IM_SESSION_GROUP_START: - case IM_SESSION_CONFERENCE_START: - case IM_SESSION_SEND: - case IM_SESSION_LEAVE: - //IM_FROM_TASK - case IM_BUSY_AUTO_RESPONSE: - case IM_CONSOLE_AND_CHAT_HISTORY: - case IM_LURE_USER: - case IM_LURE_ACCEPTED: - case IM_LURE_DECLINED: - case IM_GODLIKE_LURE_USER: - case IM_YET_TO_BE_USED: - case IM_GROUP_ELECTION_DEPRECATED: - //IM_GOTO_URL - //IM_FROM_TASK_AS_ALERT - case IM_GROUP_NOTICE: - case IM_GROUP_NOTICE_INVENTORY_ACCEPTED: - case IM_GROUP_NOTICE_INVENTORY_DECLINED: - case IM_GROUP_INVITATION_ACCEPT: - case IM_GROUP_INVITATION_DECLINE: - case IM_GROUP_NOTICE_REQUESTED: - case IM_FRIENDSHIP_OFFERED: - case IM_FRIENDSHIP_ACCEPTED: - case IM_FRIENDSHIP_DECLINED_DEPRECATED: - //IM_TYPING_START - //IM_TYPING_STOP - return LLCacheName::cleanFullName(name); - default: - return name; - } -} - -static std::string clean_name_from_task_im(const std::string& msg, - BOOL from_group) -{ - boost::smatch match; - static const boost::regex returned_exp( - "(.*been returned to your inventory lost and found folder by )(.+)( (from|near).*)"); - if (boost::regex_match(msg, match, returned_exp)) - { - // match objects are 1-based for groups - std::string final = match[1].str(); - std::string name = match[2].str(); - // Don't try to clean up group names - if (!from_group) - { - if (LLAvatarNameCache::useDisplayNames()) - { - // ...just convert to username - final += LLCacheName::buildUsername(name); - } - else - { - // ...strip out legacy "Resident" name - final += LLCacheName::cleanFullName(name); - } - } - final += match[3].str(); - return final; - } - return msg; -} - -void notification_display_name_callback(const LLUUID& id, - const LLAvatarName& av_name, - const std::string& name, - LLSD& substitutions, - const LLSD& payload) -{ - substitutions["NAME"] = av_name.mDisplayName; - LLNotificationsUtil::add(name, substitutions, payload); -} - -class LLPostponedIMSystemTipNotification: public LLPostponedNotification -{ -protected: - /* virtual */ - void modifyNotificationParams() - { - LLSD payload = mParams.payload; - payload["SESSION_NAME"] = mName; - mParams.payload = payload; - } - -}; - -// Callback for name resolution of a god/estate message -void god_message_name_cb(const LLAvatarName& av_name, LLChat chat, std::string message) -{ - LLSD args; - args["NAME"] = av_name.getCompleteName(); - args["MESSAGE"] = message; - LLNotificationsUtil::add("GodMessage", args); - - // Treat like a system message and put in chat history. - chat.mText = av_name.getCompleteName() + ": " + message; - - LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD()); - if(nearby_chat) - { - nearby_chat->addMessage(chat); - } - -} - -void process_improved_im(LLMessageSystem *msg, void **user_data) -{ - if (gNoRender) - { - return; - } - LLUUID from_id; - BOOL from_group; - LLUUID to_id; - U8 offline; - U8 d = 0; - LLUUID session_id; - U32 timestamp; - std::string name; - std::string message; - U32 parent_estate_id = 0; - LLUUID region_id; - LLVector3 position; - U8 binary_bucket[MTUBYTES]; - S32 binary_bucket_size; - LLChat chat; - std::string buffer; - - // *TODO: Translate - need to fix the full name to first/last (maybe) - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, from_id); - msg->getBOOLFast(_PREHASH_MessageBlock, _PREHASH_FromGroup, from_group); - msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ToAgentID, to_id); - msg->getU8Fast( _PREHASH_MessageBlock, _PREHASH_Offline, offline); - msg->getU8Fast( _PREHASH_MessageBlock, _PREHASH_Dialog, d); - msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ID, session_id); - msg->getU32Fast( _PREHASH_MessageBlock, _PREHASH_Timestamp, timestamp); - //msg->getData("MessageBlock", "Count", &count); - msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_FromAgentName, name); - msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_Message, message); - msg->getU32Fast(_PREHASH_MessageBlock, _PREHASH_ParentEstateID, parent_estate_id); - msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_RegionID, region_id); - msg->getVector3Fast(_PREHASH_MessageBlock, _PREHASH_Position, position); - msg->getBinaryDataFast( _PREHASH_MessageBlock, _PREHASH_BinaryBucket, binary_bucket, 0, 0, MTUBYTES); - binary_bucket_size = msg->getSizeFast(_PREHASH_MessageBlock, _PREHASH_BinaryBucket); - EInstantMessage dialog = (EInstantMessage)d; - - // make sure that we don't have an empty or all-whitespace name - LLStringUtil::trim(name); - if (name.empty()) - { - name = LLTrans::getString("Unnamed"); - } - // IDEVO convert new-style "Resident" names for display - name = clean_name_from_im(name, dialog); - - BOOL is_busy = gAgent.getBusy(); - BOOL is_muted = LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat); - BOOL is_linden = LLMuteList::getInstance()->isLinden(name); - BOOL is_owned_by_me = FALSE; - BOOL is_friend = (LLAvatarTracker::instance().getBuddyInfo(from_id) == NULL) ? false : true; - BOOL accept_im_from_only_friend = gSavedSettings.getBOOL("VoiceCallsFriendsOnly"); - - chat.mMuted = is_muted && !is_linden; - chat.mFromID = from_id; - chat.mFromName = name; - chat.mSourceType = (from_id.isNull() || (name == std::string(SYSTEM_FROM))) ? CHAT_SOURCE_SYSTEM : CHAT_SOURCE_AGENT; - - LLViewerObject *source = gObjectList.findObject(session_id); //Session ID is probably the wrong thing. - if (source) - { - is_owned_by_me = source->permYouOwner(); - } - - std::string separator_string(": "); - - LLSD args; - LLSD payload; - LLNotification::Params params; - - switch(dialog) - { - case IM_CONSOLE_AND_CHAT_HISTORY: - args["MESSAGE"] = message; - payload["from_id"] = from_id; - - params.name = "IMSystemMessageTip"; - params.substitutions = args; - params.payload = payload; - LLPostponedNotification::add<LLPostponedIMSystemTipNotification>(params, from_id, false); - break; - - case IM_NOTHING_SPECIAL: - // Don't show dialog, just do IM - if (!gAgent.isGodlike() - && gAgent.getRegion()->isPrelude() - && to_id.isNull() ) - { - // do nothing -- don't distract newbies in - // Prelude with global IMs - } - else if (offline == IM_ONLINE && !is_linden && is_busy && name != SYSTEM_FROM) - { - // return a standard "busy" message, but only do it to online IM - // (i.e. not other auto responses and not store-and-forward IM) - if (!gIMMgr->hasSession(session_id)) - { - // if there is not a panel for this conversation (i.e. it is a new IM conversation - // initiated by the other party) then... - std::string my_name; - LLAgentUI::buildFullname(my_name); - std::string response = gSavedPerAccountSettings.getString("BusyModeResponse"); - pack_instant_message( - gMessageSystem, - gAgent.getID(), - FALSE, - gAgent.getSessionID(), - from_id, - my_name, - response, - IM_ONLINE, - IM_BUSY_AUTO_RESPONSE, - session_id); - gAgent.sendReliableMessage(); - } - - // now store incoming IM in chat history - - buffer = message; - - LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; - - // add to IM panel, but do not bother the user - gIMMgr->addMessage( - session_id, - from_id, - name, - buffer, - LLStringUtil::null, - dialog, - parent_estate_id, - region_id, - position, - true); - } - else if (from_id.isNull()) - { - LLSD args; - args["MESSAGE"] = message; - LLNotificationsUtil::add("SystemMessage", args); - } - else if (to_id.isNull()) - { - // Message to everyone from GOD, look up the fullname since - // server always slams name to legacy names - LLAvatarNameCache::get(from_id, boost::bind(god_message_name_cb, _2, chat, message)); - } - else - { - // standard message, not from system - std::string saved; - if(offline == IM_OFFLINE) - { - LLStringUtil::format_map_t args; - args["[LONG_TIMESTAMP]"] = formatted_time(timestamp); - saved = LLTrans::getString("Saved_message", args); - } - buffer = saved + message; - - LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; - - bool mute_im = is_muted; - if(accept_im_from_only_friend&&!is_friend) - { - mute_im = true; - } - if (!mute_im || is_linden) - { - gIMMgr->addMessage( - session_id, - from_id, - name, - buffer, - LLStringUtil::null, - dialog, - parent_estate_id, - region_id, - position, - true); - } - else - { - /* - EXT-5099 - currently there is no way to store in history only... - using LLNotificationsUtil::add will add message to Nearby Chat - - // muted user, so don't start an IM session, just record line in chat - // history. Pretend the chat is from a local agent, - // so it will go into the history but not be shown on screen. - - LLSD args; - args["MESSAGE"] = buffer; - LLNotificationsUtil::add("SystemMessageTip", args); - */ - } - } - break; - - case IM_TYPING_START: - { - LLPointer<LLIMInfo> im_info = new LLIMInfo(gMessageSystem); - gIMMgr->processIMTypingStart(im_info); - } - break; - - case IM_TYPING_STOP: - { - LLPointer<LLIMInfo> im_info = new LLIMInfo(gMessageSystem); - gIMMgr->processIMTypingStop(im_info); - } - break; - - case IM_MESSAGEBOX: - { - // This is a block, modeless dialog. - //*TODO: Translate - args["MESSAGE"] = message; - LLNotificationsUtil::add("SystemMessageTip", args); - } - break; - case IM_GROUP_NOTICE: - case IM_GROUP_NOTICE_REQUESTED: - { - LL_INFOS("Messaging") << "Received IM_GROUP_NOTICE message." << LL_ENDL; - // Read the binary bucket for more information. - struct notice_bucket_header_t - { - U8 has_inventory; - U8 asset_type; - LLUUID group_id; - }; - struct notice_bucket_full_t - { - struct notice_bucket_header_t header; - U8 item_name[DB_INV_ITEM_NAME_BUF_SIZE]; - }* notice_bin_bucket; - - // Make sure the binary bucket is big enough to hold the header - // and a null terminated item name. - if ( (binary_bucket_size < (S32)((sizeof(notice_bucket_header_t) + sizeof(U8)))) - || (binary_bucket[binary_bucket_size - 1] != '\0') ) - { - LL_WARNS("Messaging") << "Malformed group notice binary bucket" << LL_ENDL; - break; - } - - notice_bin_bucket = (struct notice_bucket_full_t*) &binary_bucket[0]; - U8 has_inventory = notice_bin_bucket->header.has_inventory; - U8 asset_type = notice_bin_bucket->header.asset_type; - LLUUID group_id = notice_bin_bucket->header.group_id; - std::string item_name = ll_safe_string((const char*) notice_bin_bucket->item_name); - - // If there is inventory, give the user the inventory offer. - LLOfferInfo* info = NULL; - - if (has_inventory) - { - info = new LLOfferInfo(); - - info->mIM = IM_GROUP_NOTICE; - info->mFromID = from_id; - info->mFromGroup = from_group; - info->mTransactionID = session_id; - info->mType = (LLAssetType::EType) asset_type; - info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType)); - std::string from_name; - - from_name += "A group member named "; - from_name += name; - - info->mFromName = from_name; - info->mDesc = item_name; - info->mHost = msg->getSender(); - } - - std::string str(message); - - // Tokenize the string. - // TODO: Support escaped tokens ("||" -> "|") - typedef boost::tokenizer<boost::char_separator<char> > tokenizer; - boost::char_separator<char> sep("|","",boost::keep_empty_tokens); - tokenizer tokens(str, sep); - tokenizer::iterator iter = tokens.begin(); - - std::string subj(*iter++); - std::string mes(*iter++); - - // Send the notification down the new path. - // For requested notices, we don't want to send the popups. - if (dialog != IM_GROUP_NOTICE_REQUESTED) - { - payload["subject"] = subj; - payload["message"] = mes; - payload["sender_name"] = name; - payload["group_id"] = group_id; - payload["inventory_name"] = item_name; - payload["inventory_offer"] = info ? info->asLLSD() : LLSD(); - - LLSD args; - args["SUBJECT"] = subj; - args["MESSAGE"] = mes; - LLNotifications::instance().add(LLNotification::Params("GroupNotice").substitutions(args).payload(payload).time_stamp(timestamp)); - } - - // Also send down the old path for now. - if (IM_GROUP_NOTICE_REQUESTED == dialog) - { - - LLPanelGroup::showNotice(subj,mes,group_id,has_inventory,item_name,info); - } - else - { - delete info; - } - } - break; - case IM_GROUP_INVITATION: - { - //if (!is_linden && (is_busy || is_muted)) - if ((is_busy || is_muted)) - { - LLMessageSystem *msg = gMessageSystem; - busy_message(msg,from_id); - } - else - { - LL_INFOS("Messaging") << "Received IM_GROUP_INVITATION message." << LL_ENDL; - // Read the binary bucket for more information. - struct invite_bucket_t - { - S32 membership_fee; - LLUUID role_id; - }* invite_bucket; - - // Make sure the binary bucket is the correct size. - if (binary_bucket_size != sizeof(invite_bucket_t)) - { - LL_WARNS("Messaging") << "Malformed group invite binary bucket" << LL_ENDL; - break; - } - - invite_bucket = (struct invite_bucket_t*) &binary_bucket[0]; - S32 membership_fee = ntohl(invite_bucket->membership_fee); - - LLSD payload; - payload["transaction_id"] = session_id; - payload["group_id"] = from_id; - payload["name"] = name; - payload["message"] = message; - payload["fee"] = membership_fee; - - LLSD args; - args["MESSAGE"] = message; - // we shouldn't pass callback functor since it is registered in LLFunctorRegistration - LLNotificationsUtil::add("JoinGroup", args, payload); - } - } - break; - - case IM_INVENTORY_OFFERED: - case IM_TASK_INVENTORY_OFFERED: - // Someone has offered us some inventory. - { - LLOfferInfo* info = new LLOfferInfo; - if (IM_INVENTORY_OFFERED == dialog) - { - struct offer_agent_bucket_t - { - S8 asset_type; - LLUUID object_id; - }* bucketp; - - if (sizeof(offer_agent_bucket_t) != binary_bucket_size) - { - LL_WARNS("Messaging") << "Malformed inventory offer from agent" << LL_ENDL; - delete info; - break; - } - bucketp = (struct offer_agent_bucket_t*) &binary_bucket[0]; - info->mType = (LLAssetType::EType) bucketp->asset_type; - info->mObjectID = bucketp->object_id; - } - else - { - if (sizeof(S8) != binary_bucket_size) - { - LL_WARNS("Messaging") << "Malformed inventory offer from object" << LL_ENDL; - delete info; - break; - } - info->mType = (LLAssetType::EType) binary_bucket[0]; - info->mObjectID = LLUUID::null; - } - - info->mIM = dialog; - info->mFromID = from_id; - info->mFromGroup = from_group; - info->mTransactionID = session_id; - info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType)); - - if (dialog == IM_TASK_INVENTORY_OFFERED) - { - info->mFromObject = TRUE; - } - else - { - info->mFromObject = FALSE; - } - info->mFromName = name; - info->mDesc = message; - info->mHost = msg->getSender(); - //if (((is_busy && !is_owned_by_me) || is_muted)) - if (is_muted) - { - // Prefetch the offered item so that it can be discarded by the appropriate observer. (EXT-4331) - LLInventoryFetchItemsObserver* fetch_item = new LLInventoryFetchItemsObserver(info->mObjectID); - fetch_item->startFetch(); - delete fetch_item; - - // Same as closing window - info->forceResponse(IOR_DECLINE); - } - else - { - inventory_offer_handler(info); - } - } - break; - - case IM_INVENTORY_ACCEPTED: - { - args["NAME"] = LLSLURL("agent", from_id, "completename").getSLURLString();; - LLSD payload; - payload["from_id"] = from_id; - LLNotificationsUtil::add("InventoryAccepted", args, payload); - break; - } - case IM_INVENTORY_DECLINED: - { - args["NAME"] = LLSLURL("agent", from_id, "completename").getSLURLString();; - LLSD payload; - payload["from_id"] = from_id; - LLNotificationsUtil::add("InventoryDeclined", args, payload); - break; - } - // TODO: _DEPRECATED suffix as part of vote removal - DEV-24856 - case IM_GROUP_VOTE: - { - LL_WARNS("Messaging") << "Received IM: IM_GROUP_VOTE_DEPRECATED" << LL_ENDL; - } - break; - - case IM_GROUP_ELECTION_DEPRECATED: - { - LL_WARNS("Messaging") << "Received IM: IM_GROUP_ELECTION_DEPRECATED" << LL_ENDL; - } - break; - - case IM_SESSION_SEND: - { - if (!is_linden && is_busy) - { - return; - } - - // Only show messages if we have a session open (which - // should happen after you get an "invitation" - if ( !gIMMgr->hasSession(session_id) ) - { - return; - } - - // standard message, not from system - std::string saved; - if(offline == IM_OFFLINE) - { - saved = llformat("(Saved %s) ", formatted_time(timestamp).c_str()); - } - buffer = saved + message; - BOOL is_this_agent = FALSE; - if(from_id == gAgentID) - { - is_this_agent = TRUE; - } - gIMMgr->addMessage( - session_id, - from_id, - name, - buffer, - ll_safe_string((char*)binary_bucket), - IM_SESSION_INVITE, - parent_estate_id, - region_id, - position, - true); - } - break; - - case IM_FROM_TASK: - { - if (is_busy && !is_owned_by_me) - { - return; - } - - // Build a link to open the object IM info window. - std::string location = ll_safe_string((char*)binary_bucket, binary_bucket_size-1); - - if (session_id.notNull()) - { - chat.mFromID = session_id; - } - else - { - // This message originated on a region without the updated code for task id and slurl information. - // We just need a unique ID for this object that isn't the owner ID. - // If it is the owner ID it will overwrite the style that contains the link to that owner's profile. - // This isn't ideal - it will make 1 style for all objects owned by the the same person/group. - // This works because the only thing we can really do in this case is show the owner name and link to their profile. - chat.mFromID = from_id ^ gAgent.getSessionID(); - } - - chat.mSourceType = CHAT_SOURCE_OBJECT; - - if(SYSTEM_FROM == name) - { - // System's UUID is NULL (fixes EXT-4766) - chat.mFromID = LLUUID::null; - chat.mSourceType = CHAT_SOURCE_SYSTEM; - } - - // IDEVO Some messages have embedded resident names - message = clean_name_from_task_im(message, from_group); - - LLSD query_string; - query_string["owner"] = from_id; - query_string["slurl"] = location; - query_string["name"] = name; - if (from_group) - { - query_string["groupowned"] = "true"; - } - - chat.mURL = LLSLURL("objectim", session_id, "").getSLURLString(); - chat.mText = message; - - // Note: lie to Nearby Chat, pretending that this is NOT an IM, because - // IMs from obejcts don't open IM sessions. - LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD()); - if(SYSTEM_FROM != name && nearby_chat) - { - chat.mOwnerID = from_id; - LLSD args; - args["slurl"] = location; - args["type"] = LLNotificationsUI::NT_NEARBYCHAT; - - // Look for IRC-style emotes here so object name formatting is correct - std::string prefix = message.substr(0, 4); - if (prefix == "/me " || prefix == "/me'") - { - chat.mChatStyle = CHAT_STYLE_IRC; - } - - LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args); - } - - - //Object IMs send with from name: 'Second Life' need to be displayed also in notification toasts (EXT-1590) - if (SYSTEM_FROM != name) break; - - LLSD substitutions; - substitutions["NAME"] = name; - substitutions["MSG"] = message; - - LLSD payload; - payload["object_id"] = session_id; - payload["owner_id"] = from_id; - payload["from_id"] = from_id; - payload["slurl"] = location; - payload["name"] = name; - std::string session_name; - if (from_group) - { - payload["group_owned"] = "true"; - } - - LLNotification::Params params("ServerObjectMessage"); - params.substitutions = substitutions; - params.payload = payload; - - LLPostponedNotification::add<LLPostponedServerObjectNotification>(params, from_id, from_group); - } - break; - case IM_FROM_TASK_AS_ALERT: - if (is_busy && !is_owned_by_me) - { - return; - } - { - // Construct a viewer alert for this message. - args["NAME"] = name; - args["MESSAGE"] = message; - LLNotificationsUtil::add("ObjectMessage", args); - } - break; - case IM_BUSY_AUTO_RESPONSE: - if (is_muted) - { - LL_DEBUGS("Messaging") << "Ignoring busy response from " << from_id << LL_ENDL; - return; - } - else - { - // TODO: after LLTrans hits release, get "busy response" into translatable file - buffer = llformat("%s (%s): %s", name.c_str(), "busy response", message.c_str()); - gIMMgr->addMessage(session_id, from_id, name, buffer); - } - break; - - case IM_LURE_USER: - { - if (is_muted) - { - return; - } - else if (is_busy) - { - busy_message(msg,from_id); - } - else - { - LLVector3 pos, look_at; - U64 region_handle; - U8 region_access = SIM_ACCESS_MIN; - std::string region_info = ll_safe_string((char*)binary_bucket, binary_bucket_size); - std::string region_access_str = LLStringUtil::null; - std::string region_access_icn = LLStringUtil::null; - - if (parse_lure_bucket(region_info, region_handle, pos, look_at, region_access)) - { - region_access_str = LLViewerRegion::accessToString(region_access); - region_access_icn = LLViewerRegion::getAccessIcon(region_access); - } - - LLSD args; - // *TODO: Translate -> [FIRST] [LAST] (maybe) - args["NAME_SLURL"] = LLSLURL("agent", from_id, "about").getSLURLString(); - args["MESSAGE"] = message; - args["MATURITY_STR"] = region_access_str; - args["MATURITY_ICON"] = region_access_icn; - LLSD payload; - payload["from_id"] = from_id; - payload["lure_id"] = session_id; - payload["godlike"] = FALSE; - - LLNotification::Params params("TeleportOffered"); - params.substitutions = args; - params.payload = payload; - LLPostponedNotification::add<LLPostponedOfferNotification>( params, from_id, false); - } - } - break; - - case IM_GODLIKE_LURE_USER: - { - LLSD payload; - payload["from_id"] = from_id; - payload["lure_id"] = session_id; - payload["godlike"] = TRUE; - // do not show a message box, because you're about to be - // teleported. - LLNotifications::instance().forceResponse(LLNotification::Params("TeleportOffered").payload(payload), 0); - } - break; - - case IM_GOTO_URL: - { - LLSD args; - // n.b. this is for URLs sent by the system, not for - // URLs sent by scripts (i.e. llLoadURL) - if (binary_bucket_size <= 0) - { - LL_WARNS("Messaging") << "bad binary_bucket_size: " - << binary_bucket_size - << " - aborting function." << LL_ENDL; - return; - } - - std::string url; - - url.assign((char*)binary_bucket, binary_bucket_size-1); - args["MESSAGE"] = message; - args["URL"] = url; - LLSD payload; - payload["url"] = url; - LLNotificationsUtil::add("GotoURL", args, payload ); - } - break; - - case IM_FRIENDSHIP_OFFERED: - { - LLSD payload; - payload["from_id"] = from_id; - payload["session_id"] = session_id;; - payload["online"] = (offline == IM_ONLINE); - payload["sender"] = msg->getSender().getIPandPort(); - - if (is_busy) - { - busy_message(msg, from_id); - LLNotifications::instance().forceResponse(LLNotification::Params("OfferFriendship").payload(payload), 1); - } - else if (is_muted) - { - LLNotifications::instance().forceResponse(LLNotification::Params("OfferFriendship").payload(payload), 1); - } - else - { - args["NAME_SLURL"] = LLSLURL("agent", from_id, "about").getSLURLString(); - if(message.empty()) - { - //support for frienship offers from clients before July 2008 - LLNotificationsUtil::add("OfferFriendshipNoMessage", args, payload); - } - else - { - args["[MESSAGE]"] = message; - LLNotification::Params params("OfferFriendship"); - params.substitutions = args; - params.payload = payload; - LLPostponedNotification::add<LLPostponedOfferNotification>( params, from_id, false); - } - } - } - break; - - case IM_FRIENDSHIP_ACCEPTED: - { - // In the case of an offline IM, the formFriendship() may be extraneous - // as the database should already include the relationship. But it - // doesn't hurt for dupes. - LLAvatarTracker::formFriendship(from_id); - - std::vector<std::string> strings; - strings.push_back(from_id.asString()); - send_generic_message("requestonlinenotification", strings); - - args["NAME"] = name; - LLSD payload; - payload["from_id"] = from_id; - LLAvatarNameCache::get(from_id, boost::bind(¬ification_display_name_callback, - _1, - _2, - "FriendshipAccepted", - args, - payload)); - } - break; - - case IM_FRIENDSHIP_DECLINED_DEPRECATED: - default: - LL_WARNS("Messaging") << "Instant message calling for unknown dialog " - << (S32)dialog << LL_ENDL; - break; - } - - LLWindow* viewer_window = gViewerWindow->getWindow(); - if (viewer_window && viewer_window->getMinimized()) - { - viewer_window->flashIcon(5.f); - } -} - -void busy_message (LLMessageSystem* msg, LLUUID from_id) -{ - if (gAgent.getBusy()) - { - std::string my_name; - LLAgentUI::buildFullname(my_name); - std::string response = gSavedPerAccountSettings.getString("BusyModeResponse"); - pack_instant_message( - gMessageSystem, - gAgent.getID(), - FALSE, - gAgent.getSessionID(), - from_id, - my_name, - response, - IM_ONLINE, - IM_BUSY_AUTO_RESPONSE); - gAgent.sendReliableMessage(); - } -} - -bool callingcard_offer_callback(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - LLUUID fid; - LLUUID from_id; - LLMessageSystem* msg = gMessageSystem; - switch(option) - { - case 0: - // accept - msg->newMessageFast(_PREHASH_AcceptCallingCard); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_TransactionBlock); - msg->addUUIDFast(_PREHASH_TransactionID, notification["payload"]["transaction_id"].asUUID()); - fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); - msg->nextBlockFast(_PREHASH_FolderData); - msg->addUUIDFast(_PREHASH_FolderID, fid); - msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); - break; - case 1: - // decline - msg->newMessageFast(_PREHASH_DeclineCallingCard); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_TransactionBlock); - msg->addUUIDFast(_PREHASH_TransactionID, notification["payload"]["transaction_id"].asUUID()); - msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); - busy_message(msg, notification["payload"]["source_id"].asUUID()); - break; - default: - // close button probably, possibly timed out - break; - } - - return false; -} -static LLNotificationFunctorRegistration callingcard_offer_cb_reg("OfferCallingCard", callingcard_offer_callback); - -void process_offer_callingcard(LLMessageSystem* msg, void**) -{ - // someone has offered to form a friendship - LL_DEBUGS("Messaging") << "callingcard offer" << LL_ENDL; - - LLUUID source_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, source_id); - LLUUID tid; - msg->getUUIDFast(_PREHASH_AgentBlock, _PREHASH_TransactionID, tid); - - LLSD payload; - payload["transaction_id"] = tid; - payload["source_id"] = source_id; - payload["sender"] = msg->getSender().getIPandPort(); - - LLViewerObject* source = gObjectList.findObject(source_id); - LLSD args; - std::string source_name; - if(source && source->isAvatar()) - { - LLNameValue* nvfirst = source->getNVPair("FirstName"); - LLNameValue* nvlast = source->getNVPair("LastName"); - if (nvfirst && nvlast) - { - source_name = LLCacheName::buildFullName( - nvfirst->getString(), nvlast->getString()); - } - } - - if(!source_name.empty()) - { - if (gAgent.getBusy() - || LLMuteList::getInstance()->isMuted(source_id, source_name, LLMute::flagTextChat)) - { - // automatically decline offer - LLNotifications::instance().forceResponse(LLNotification::Params("OfferCallingCard").payload(payload), 1); - } - else - { - args["NAME"] = source_name; - LLNotificationsUtil::add("OfferCallingCard", args, payload); - } - } - else - { - LL_WARNS("Messaging") << "Calling card offer from an unknown source." << LL_ENDL; - } -} - -void process_accept_callingcard(LLMessageSystem* msg, void**) -{ - LLNotificationsUtil::add("CallingCardAccepted"); -} - -void process_decline_callingcard(LLMessageSystem* msg, void**) -{ - LLNotificationsUtil::add("CallingCardDeclined"); -} - -class ChatTranslationReceiver : public LLTranslate::TranslationReceiver -{ -public : - ChatTranslationReceiver(const std::string &from_lang, const std::string &to_lang, const std::string &mesg, - const LLChat &chat, const LLSD &toast_args) - : LLTranslate::TranslationReceiver(from_lang, to_lang), - m_chat(chat), - m_toastArgs(toast_args), - m_origMesg(mesg) - { - } - - static boost::intrusive_ptr<ChatTranslationReceiver> build(const std::string &from_lang, const std::string &to_lang, const std::string &mesg, const LLChat &chat, const LLSD &toast_args) - { - return boost::intrusive_ptr<ChatTranslationReceiver>(new ChatTranslationReceiver(from_lang, to_lang, mesg, chat, toast_args)); - } - -protected: - void handleResponse(const std::string &translation, const std::string &detected_language) - { - // filter out non-interesting responeses - if ( !translation.empty() - && (m_toLang != detected_language) - && (LLStringUtil::compareInsensitive(translation, m_origMesg) != 0) ) - { - m_chat.mText += " (" + translation + ")"; - } - - LLNotificationsUI::LLNotificationManager::instance().onChat(m_chat, m_toastArgs); - } - - void handleFailure() - { - LLTranslate::TranslationReceiver::handleFailure(); - m_chat.mText += " (?)"; - - LLNotificationsUI::LLNotificationManager::instance().onChat(m_chat, m_toastArgs); - } - -private: - LLChat m_chat; - std::string m_origMesg; - LLSD m_toastArgs; -}; -void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) -{ - LLChat chat; - std::string mesg; - std::string from_name; - U8 source_temp; - U8 type_temp; - U8 audible_temp; - LLColor4 color(1.0f, 1.0f, 1.0f, 1.0f); - LLUUID from_id; - LLUUID owner_id; - BOOL is_owned_by_me = FALSE; - LLViewerObject* chatter; - - msg->getString("ChatData", "FromName", from_name); - - msg->getUUID("ChatData", "SourceID", from_id); - chat.mFromID = from_id; - - // Object owner for objects - msg->getUUID("ChatData", "OwnerID", owner_id); - - msg->getU8Fast(_PREHASH_ChatData, _PREHASH_SourceType, source_temp); - chat.mSourceType = (EChatSourceType)source_temp; - - msg->getU8("ChatData", "ChatType", type_temp); - chat.mChatType = (EChatType)type_temp; - - msg->getU8Fast(_PREHASH_ChatData, _PREHASH_Audible, audible_temp); - chat.mAudible = (EChatAudible)audible_temp; - - chat.mTime = LLFrameTimer::getElapsedSeconds(); - - // IDEVO Correct for new-style "Resident" names - if (chat.mSourceType == CHAT_SOURCE_AGENT) - { - // I don't know if it's OK to change this here, if - // anything downstream does lookups by name, for instance - - LLAvatarName av_name; - if (LLAvatarNameCache::get(from_id, &av_name)) - { - chat.mFromName = av_name.mDisplayName; - } - else - { - chat.mFromName = LLCacheName::cleanFullName(from_name); - } - } - else - { - chat.mFromName = from_name; - } - - BOOL is_busy = gAgent.getBusy(); - - BOOL is_muted = FALSE; - BOOL is_linden = FALSE; - is_muted = LLMuteList::getInstance()->isMuted( - from_id, - from_name, - LLMute::flagTextChat) - || LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagTextChat); - is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT && - LLMuteList::getInstance()->isLinden(from_name); - - BOOL is_audible = (CHAT_AUDIBLE_FULLY == chat.mAudible); - chatter = gObjectList.findObject(from_id); - if (chatter) - { - chat.mPosAgent = chatter->getPositionAgent(); - - // Make swirly things only for talking objects. (not script debug messages, though) - if (chat.mSourceType == CHAT_SOURCE_OBJECT - && chat.mChatType != CHAT_TYPE_DEBUG_MSG - && gSavedSettings.getBOOL("EffectScriptChatParticles") ) - { - LLPointer<LLViewerPartSourceChat> psc = new LLViewerPartSourceChat(chatter->getPositionAgent()); - psc->setSourceObject(chatter); - psc->setColor(color); - //We set the particles to be owned by the object's owner, - //just in case they should be muted by the mute list - psc->setOwnerUUID(owner_id); - LLViewerPartSim::getInstance()->addPartSource(psc); - } - - // record last audible utterance - if (is_audible - && (is_linden || (!is_muted && !is_busy))) - { - if (chat.mChatType != CHAT_TYPE_START - && chat.mChatType != CHAT_TYPE_STOP) - { - gAgent.heardChat(chat.mFromID); - } - } - - is_owned_by_me = chatter->permYouOwner(); - } - - if (is_audible) - { - BOOL visible_in_chat_bubble = FALSE; - std::string verb; - - color.setVec(1.f,1.f,1.f,1.f); - msg->getStringFast(_PREHASH_ChatData, _PREHASH_Message, mesg); - - BOOL ircstyle = FALSE; - - // Look for IRC-style emotes here so chatbubbles work - std::string prefix = mesg.substr(0, 4); - if (prefix == "/me " || prefix == "/me'") - { - ircstyle = TRUE; - } - chat.mText = mesg; - - // Look for the start of typing so we can put "..." in the bubbles. - if (CHAT_TYPE_START == chat.mChatType) - { - LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, TRUE); - - // Might not have the avatar constructed yet, eg on login. - if (chatter && chatter->isAvatar()) - { - ((LLVOAvatar*)chatter)->startTyping(); - } - return; - } - else if (CHAT_TYPE_STOP == chat.mChatType) - { - LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE); - - // Might not have the avatar constructed yet, eg on login. - if (chatter && chatter->isAvatar()) - { - ((LLVOAvatar*)chatter)->stopTyping(); - } - return; - } - - // Look for IRC-style emotes - if (ircstyle) - { - // set CHAT_STYLE_IRC to avoid adding Avatar Name as author of message. See EXT-656 - chat.mChatStyle = CHAT_STYLE_IRC; - - // Do nothing, ircstyle is fixed above for chat bubbles - } - else - { - switch(chat.mChatType) - { - case CHAT_TYPE_WHISPER: - verb = LLTrans::getString("whisper") + " "; - break; - case CHAT_TYPE_DEBUG_MSG: - case CHAT_TYPE_OWNER: - case CHAT_TYPE_NORMAL: - verb = ""; - break; - case CHAT_TYPE_SHOUT: - verb = LLTrans::getString("shout") + " "; - break; - case CHAT_TYPE_START: - case CHAT_TYPE_STOP: - LL_WARNS("Messaging") << "Got chat type start/stop in main chat processing." << LL_ENDL; - break; - default: - LL_WARNS("Messaging") << "Unknown type " << chat.mChatType << " in chat!" << LL_ENDL; - verb = ""; - break; - } - - - chat.mText = ""; - chat.mText += verb; - chat.mText += mesg; - } - - // We have a real utterance now, so can stop showing "..." and proceed. - if (chatter && chatter->isAvatar()) - { - LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE); - ((LLVOAvatar*)chatter)->stopTyping(); - - if (!is_muted && !is_busy) - { - visible_in_chat_bubble = gSavedSettings.getBOOL("UseChatBubbles"); - std::string formated_msg = ""; - LLViewerChat::formatChatMsg(chat, formated_msg); - LLChat chat_bubble = chat; - chat_bubble.mText = formated_msg; - ((LLVOAvatar*)chatter)->addChat(chat_bubble); - } - } - - if (chatter) - { - chat.mPosAgent = chatter->getPositionAgent(); - } - - // truth table: - // LINDEN BUSY MUTED OWNED_BY_YOU TASK DISPLAY STORE IN HISTORY - // F F F F * Yes Yes - // F F F T * Yes Yes - // F F T F * No No - // F F T T * No No - // F T F F * No Yes - // F T F T * Yes Yes - // F T T F * No No - // F T T T * No No - // T * * * F Yes Yes - - chat.mMuted = is_muted && !is_linden; - - // pass owner_id to chat so that we can display the remote - // object inspect for an object that is chatting with you - LLSD args; - args["type"] = LLNotificationsUI::NT_NEARBYCHAT; - chat.mOwnerID = owner_id; - - if (gSavedSettings.getBOOL("TranslateChat") && chat.mSourceType != CHAT_SOURCE_SYSTEM) - { - if (chat.mChatStyle == CHAT_STYLE_IRC) - { - mesg = mesg.substr(4, std::string::npos); - } - const std::string from_lang = ""; // leave empty to trigger autodetect - const std::string to_lang = LLTranslate::getTranslateLanguage(); - - LLHTTPClient::ResponderPtr result = ChatTranslationReceiver::build(from_lang, to_lang, mesg, chat, args); - LLTranslate::translateMessage(result, from_lang, to_lang, mesg); - } - else - { - LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args); - } - } -} - - -// Simulator we're on is informing the viewer that the agent -// is starting to teleport (perhaps to another sim, perhaps to the -// same sim). If we initiated the teleport process by sending some kind -// of TeleportRequest, then this info is redundant, but if the sim -// initiated the teleport (via a script call, being killed, etc.) -// then this info is news to us. -void process_teleport_start(LLMessageSystem *msg, void**) -{ - // on teleport, don't tell them about destination guide anymore - LLFirstUse::notUsingDestinationGuide(false); - U32 teleport_flags = 0x0; - msg->getU32("Info", "TeleportFlags", teleport_flags); - - LL_DEBUGS("Messaging") << "Got TeleportStart with TeleportFlags=" << teleport_flags << ". gTeleportDisplay: " << gTeleportDisplay << ", gAgent.mTeleportState: " << gAgent.getTeleportState() << LL_ENDL; - - if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) - { - gViewerWindow->setProgressCancelButtonVisible(FALSE); - } - else - { - gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Cancel")); - } - - // Freeze the UI and show progress bar - // Note: could add data here to differentiate between normal teleport and death. - - if( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE ) - { - gTeleportDisplay = TRUE; - gAgent.setTeleportState( LLAgent::TELEPORT_START ); - make_ui_sound("UISndTeleportOut"); - - LL_INFOS("Messaging") << "Teleport initiated by remote TeleportStart message with TeleportFlags: " << teleport_flags << LL_ENDL; - // Don't call LLFirstUse::useTeleport here because this could be - // due to being killed, which would send you home, not to a Telehub - } -} - -void process_teleport_progress(LLMessageSystem* msg, void**) -{ - LLUUID agent_id; - msg->getUUID("AgentData", "AgentID", agent_id); - if((gAgent.getID() != agent_id) - || (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE)) - { - LL_WARNS("Messaging") << "Unexpected teleport progress message." << LL_ENDL; - return; - } - U32 teleport_flags = 0x0; - msg->getU32("Info", "TeleportFlags", teleport_flags); - if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL) - { - gViewerWindow->setProgressCancelButtonVisible(FALSE); - } - else - { - gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Cancel")); - } - std::string buffer; - msg->getString("Info", "Message", buffer); - LL_DEBUGS("Messaging") << "teleport progress: " << buffer << LL_ENDL; - - //Sorta hacky...default to using simulator raw messages - //if we don't find the coresponding mapping in our progress mappings - std::string message = buffer; - - if (LLAgent::sTeleportProgressMessages.find(buffer) != - LLAgent::sTeleportProgressMessages.end() ) - { - message = LLAgent::sTeleportProgressMessages[buffer]; - } - - gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages[message]); -} - -class LLFetchInWelcomeArea : public LLInventoryFetchDescendentsObserver -{ -public: - LLFetchInWelcomeArea(const uuid_vec_t &ids) : - LLInventoryFetchDescendentsObserver(ids) - {} - virtual void done() - { - LLIsType is_landmark(LLAssetType::AT_LANDMARK); - LLIsType is_card(LLAssetType::AT_CALLINGCARD); - - LLInventoryModel::cat_array_t card_cats; - LLInventoryModel::item_array_t card_items; - LLInventoryModel::cat_array_t land_cats; - LLInventoryModel::item_array_t land_items; - - uuid_vec_t::iterator it = mComplete.begin(); - uuid_vec_t::iterator end = mComplete.end(); - for(; it != end; ++it) - { - gInventory.collectDescendentsIf( - (*it), - land_cats, - land_items, - LLInventoryModel::EXCLUDE_TRASH, - is_landmark); - gInventory.collectDescendentsIf( - (*it), - card_cats, - card_items, - LLInventoryModel::EXCLUDE_TRASH, - is_card); - } - LLSD args; - if ( land_items.count() > 0 ) - { // Show notification that they can now teleport to landmarks. Use a random landmark from the inventory - S32 random_land = ll_rand( land_items.count() - 1 ); - args["NAME"] = land_items[random_land]->getName(); - LLNotificationsUtil::add("TeleportToLandmark",args); - } - if ( card_items.count() > 0 ) - { // Show notification that they can now contact people. Use a random calling card from the inventory - S32 random_card = ll_rand( card_items.count() - 1 ); - args["NAME"] = card_items[random_card]->getName(); - LLNotificationsUtil::add("TeleportToPerson",args); - } - - gInventory.removeObserver(this); - delete this; - } -}; - - - -class LLPostTeleportNotifiers : public LLEventTimer -{ -public: - LLPostTeleportNotifiers(); - virtual ~LLPostTeleportNotifiers(); - - //function to be called at the supplied frequency - virtual BOOL tick(); -}; - -LLPostTeleportNotifiers::LLPostTeleportNotifiers() : LLEventTimer( 2.0 ) -{ -}; - -LLPostTeleportNotifiers::~LLPostTeleportNotifiers() -{ -} - -BOOL LLPostTeleportNotifiers::tick() -{ - BOOL all_done = FALSE; - if ( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE ) - { - // get callingcards and landmarks available to the user arriving. - uuid_vec_t folders; - const LLUUID callingcard_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD); - if(callingcard_id.notNull()) - folders.push_back(callingcard_id); - const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK); - if(folder_id.notNull()) - folders.push_back(folder_id); - if(!folders.empty()) - { - LLFetchInWelcomeArea* fetcher = new LLFetchInWelcomeArea(folders); - fetcher->startFetch(); - if(fetcher->isFinished()) - { - fetcher->done(); - } - else - { - gInventory.addObserver(fetcher); - } - } - all_done = TRUE; - } - - return all_done; -} - - - -// Teleport notification from the simulator -// We're going to pretend to be a new agent -void process_teleport_finish(LLMessageSystem* msg, void**) -{ - LL_DEBUGS("Messaging") << "Got teleport location message" << LL_ENDL; - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_Info, _PREHASH_AgentID, agent_id); - if (agent_id != gAgent.getID()) - { - LL_WARNS("Messaging") << "Got teleport notification for wrong agent!" << LL_ENDL; - return; - } - - // Teleport is finished; it can't be cancelled now. - gViewerWindow->setProgressCancelButtonVisible(FALSE); - - // Do teleport effect for where you're leaving - // VEFFECT: TeleportStart - LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); - effectp->setPositionGlobal(gAgent.getPositionGlobal()); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - LLHUDManager::getInstance()->sendEffects(); - - U32 location_id; - U32 sim_ip; - U16 sim_port; - LLVector3 pos, look_at; - U64 region_handle; - msg->getU32Fast(_PREHASH_Info, _PREHASH_LocationID, location_id); - msg->getIPAddrFast(_PREHASH_Info, _PREHASH_SimIP, sim_ip); - msg->getIPPortFast(_PREHASH_Info, _PREHASH_SimPort, sim_port); - //msg->getVector3Fast(_PREHASH_Info, _PREHASH_Position, pos); - //msg->getVector3Fast(_PREHASH_Info, _PREHASH_LookAt, look_at); - msg->getU64Fast(_PREHASH_Info, _PREHASH_RegionHandle, region_handle); - U32 teleport_flags; - msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags); - - - std::string seedCap; - msg->getStringFast(_PREHASH_Info, _PREHASH_SeedCapability, seedCap); - - // update home location if we are teleporting out of prelude - specific to teleporting to welcome area - if((teleport_flags & TELEPORT_FLAGS_SET_HOME_TO_TARGET) - && (!gAgent.isGodlike())) - { - gAgent.setHomePosRegion(region_handle, pos); - - // Create a timer that will send notices when teleporting is all finished. Since this is - // based on the LLEventTimer class, it will be managed by that class and not orphaned or leaked. - new LLPostTeleportNotifiers(); - } - - LLHost sim_host(sim_ip, sim_port); - - // Viewer trusts the simulator. - gMessageSystem->enableCircuit(sim_host, TRUE); - LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host); - -/* - // send camera update to new region - gAgentCamera.updateCamera(); - - // likewise make sure the camera is behind the avatar - gAgentCamera.resetView(TRUE); - LLVector3 shift_vector = regionp->getPosRegionFromGlobal(gAgent.getRegion()->getOriginGlobal()); - gAgent.setRegion(regionp); - gObjectList.shiftObjects(shift_vector); - - if (isAgentAvatarValid()) - { - gAgentAvatarp->clearChatText(); - gAgentCamera.slamLookAt(look_at); - } - gAgent.setPositionAgent(pos); - gAssetStorage->setUpstream(sim); - gCacheName->setUpstream(sim); -*/ - - // now, use the circuit info to tell simulator about us! - LL_INFOS("Messaging") << "process_teleport_finish() Enabling " - << sim_host << " with code " << msg->mOurCircuitCode << LL_ENDL; - msg->newMessageFast(_PREHASH_UseCircuitCode); - msg->nextBlockFast(_PREHASH_CircuitCode); - msg->addU32Fast(_PREHASH_Code, msg->getOurCircuitCode()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_ID, gAgent.getID()); - msg->sendReliable(sim_host); - - send_complete_agent_movement(sim_host); - gAgent.setTeleportState( LLAgent::TELEPORT_MOVING ); - gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages["contacting"]); - - regionp->setSeedCapability(seedCap); - - // Don't send camera updates to the new region until we're - // actually there... - - - // Now do teleport effect for where you're going. - // VEFFECT: TeleportEnd - effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE); - effectp->setPositionGlobal(gAgent.getPositionGlobal()); - - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - LLHUDManager::getInstance()->sendEffects(); - -// gTeleportDisplay = TRUE; -// gTeleportDisplayTimer.reset(); -// gViewerWindow->setShowProgress(TRUE); -} - -// stuff we have to do every time we get an AvatarInitComplete from a sim -/* -void process_avatar_init_complete(LLMessageSystem* msg, void**) -{ - LLVector3 agent_pos; - msg->getVector3Fast(_PREHASH_AvatarData, _PREHASH_Position, agent_pos); - agent_movement_complete(msg->getSender(), agent_pos); -} -*/ - -void process_agent_movement_complete(LLMessageSystem* msg, void**) -{ - gAgentMovementCompleted = true; - - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - LLUUID session_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); - if((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id)) - { - LL_WARNS("Messaging") << "Incorrect id in process_agent_movement_complete()" - << LL_ENDL; - return; - } - - LL_DEBUGS("Messaging") << "process_agent_movement_complete()" << LL_ENDL; - - // *TODO: check timestamp to make sure the movement compleation - // makes sense. - LLVector3 agent_pos; - msg->getVector3Fast(_PREHASH_Data, _PREHASH_Position, agent_pos); - LLVector3 look_at; - msg->getVector3Fast(_PREHASH_Data, _PREHASH_LookAt, look_at); - U64 region_handle; - msg->getU64Fast(_PREHASH_Data, _PREHASH_RegionHandle, region_handle); - - std::string version_channel; - msg->getString("SimData", "ChannelVersion", version_channel); - - if (!isAgentAvatarValid()) - { - // Could happen if you were immediately god-teleported away on login, - // maybe other cases. Continue, but warn. - LL_WARNS("Messaging") << "agent_movement_complete() with NULL avatarp." << LL_ENDL; - } - - F32 x, y; - from_region_handle(region_handle, &x, &y); - LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromHandle(region_handle); - if (!regionp) - { - if (gAgent.getRegion()) - { - LL_WARNS("Messaging") << "current region " << gAgent.getRegion()->getOriginGlobal() << LL_ENDL; - } - - LL_WARNS("Messaging") << "Agent being sent to invalid home region: " - << x << ":" << y - << " current pos " << gAgent.getPositionGlobal() - << LL_ENDL; - LLAppViewer::instance()->forceDisconnect(LLTrans::getString("SentToInvalidRegion")); - return; - - } - - LL_INFOS("Messaging") << "Changing home region to " << x << ":" << y << LL_ENDL; - - // set our upstream host the new simulator and shuffle things as - // appropriate. - LLVector3 shift_vector = regionp->getPosRegionFromGlobal( - gAgent.getRegion()->getOriginGlobal()); - gAgent.setRegion(regionp); - gObjectList.shiftObjects(shift_vector); - gAssetStorage->setUpstream(msg->getSender()); - gCacheName->setUpstream(msg->getSender()); - gViewerThrottle.sendToSim(); - gViewerWindow->sendShapeToSim(); - - bool is_teleport = gAgent.getTeleportState() == LLAgent::TELEPORT_MOVING; - - if( is_teleport ) - { - if (gAgent.getTeleportKeepsLookAt()) - { - // *NOTE: the LookAt data we get from the sim here doesn't - // seem to be useful, so get it from the camera instead - look_at = LLViewerCamera::getInstance()->getAtAxis(); - } - // Force the camera back onto the agent, don't animate. - gAgentCamera.setFocusOnAvatar(TRUE, FALSE); - gAgentCamera.slamLookAt(look_at); - gAgentCamera.updateCamera(); - - gAgent.setTeleportState( LLAgent::TELEPORT_START_ARRIVAL ); - - // set the appearance on teleport since the new sim does not - // know what you look like. - gAgent.sendAgentSetAppearance(); - - if (isAgentAvatarValid()) - { - // Chat the "back" SLURL. (DEV-4907) - - LLSLURL slurl; - gAgent.getTeleportSourceSLURL(slurl); - LLSD substitution = LLSD().with("[T_SLURL]", slurl.getSLURLString()); - std::string completed_from = LLAgent::sTeleportProgressMessages["completed_from"]; - LLStringUtil::format(completed_from, substitution); - - LLSD args; - args["MESSAGE"] = completed_from; - LLNotificationsUtil::add("SystemMessageTip", args); - - // Set the new position - gAgentAvatarp->setPositionAgent(agent_pos); - gAgentAvatarp->clearChat(); - gAgentAvatarp->slamPosition(); - } - } - else - { - // This is initial log-in or a region crossing - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); - - if(LLStartUp::getStartupState() < STATE_STARTED) - { // This is initial log-in, not a region crossing: - // Set the camera looking ahead of the AV so send_agent_update() below - // will report the correct location to the server. - LLVector3 look_at_point = look_at; - look_at_point = agent_pos + look_at_point.rotVec(gAgent.getQuat()); - - static LLVector3 up_direction(0.0f, 0.0f, 1.0f); - LLViewerCamera::getInstance()->lookAt(agent_pos, look_at_point, up_direction); - } - } - - if ( LLTracker::isTracking(NULL) ) - { - // Check distance to beacon, if < 5m, remove beacon - LLVector3d beacon_pos = LLTracker::getTrackedPositionGlobal(); - LLVector3 beacon_dir(agent_pos.mV[VX] - (F32)fmod(beacon_pos.mdV[VX], 256.0), agent_pos.mV[VY] - (F32)fmod(beacon_pos.mdV[VY], 256.0), 0); - if (beacon_dir.magVecSquared() < 25.f) - { - LLTracker::stopTracking(NULL); - } - else if ( is_teleport && !gAgent.getTeleportKeepsLookAt() ) - { - //look at the beacon - LLVector3 global_agent_pos = agent_pos; - global_agent_pos[0] += x; - global_agent_pos[1] += y; - look_at = (LLVector3)beacon_pos - global_agent_pos; - look_at.normVec(); - gAgentCamera.slamLookAt(look_at); - } - } - - // TODO: Put back a check for flying status! DK 12/19/05 - // Sim tells us whether the new position is off the ground - /* - if (teleport_flags & TELEPORT_FLAGS_IS_FLYING) - { - gAgent.setFlying(TRUE); - } - else - { - gAgent.setFlying(FALSE); - } - */ - - send_agent_update(TRUE, TRUE); - - if (gAgent.getRegion()->getBlockFly()) - { - gAgent.setFlying(gAgent.canFly()); - } - - // force simulator to recognize busy state - if (gAgent.getBusy()) - { - gAgent.setBusy(); - } - else - { - gAgent.clearBusy(); - } - - if (isAgentAvatarValid()) - { - gAgentAvatarp->mFootPlane.clearVec(); - } - - // send walk-vs-run status - gAgent.sendWalkRun(gAgent.getRunning() || gAgent.getAlwaysRun()); - - // If the server version has changed, display an info box and offer - // to display the release notes, unless this is the initial log in. - if (gLastVersionChannel == version_channel) - { - return; - } - - gLastVersionChannel = version_channel; -} - -void process_crossed_region(LLMessageSystem* msg, void**) -{ - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - LLUUID session_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id); - if((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id)) - { - LL_WARNS("Messaging") << "Incorrect id in process_crossed_region()" - << LL_ENDL; - return; - } - LL_INFOS("Messaging") << "process_crossed_region()" << LL_ENDL; - gAgentAvatarp->resetRegionCrossingTimer(); - - U32 sim_ip; - msg->getIPAddrFast(_PREHASH_RegionData, _PREHASH_SimIP, sim_ip); - U16 sim_port; - msg->getIPPortFast(_PREHASH_RegionData, _PREHASH_SimPort, sim_port); - LLHost sim_host(sim_ip, sim_port); - U64 region_handle; - msg->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle); - - std::string seedCap; - msg->getStringFast(_PREHASH_RegionData, _PREHASH_SeedCapability, seedCap); - - send_complete_agent_movement(sim_host); - - LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host); - regionp->setSeedCapability(seedCap); -} - - - -// Sends avatar and camera information to simulator. -// Sent roughly once per frame, or 20 times per second, whichever is less often - -const F32 THRESHOLD_HEAD_ROT_QDOT = 0.9997f; // ~= 2.5 degrees -- if its less than this we need to update head_rot -const F32 MAX_HEAD_ROT_QDOT = 0.99999f; // ~= 0.5 degrees -- if its greater than this then no need to update head_rot - // between these values we delay the updates (but no more than one second) - -static LLFastTimer::DeclareTimer FTM_AGENT_UPDATE_SEND("Send Message"); - -void send_agent_update(BOOL force_send, BOOL send_reliable) -{ - if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) - { - // We don't care if they want to send an agent update, they're not allowed to until the simulator - // that's the target is ready to receive them (after avatar_init_complete is received) - return; - } - - // We have already requested to log out. Don't send agent updates. - if(LLAppViewer::instance()->logoutRequestSent()) - { - return; - } - - // no region to send update to - if(gAgent.getRegion() == NULL) - { - return; - } - - const F32 TRANSLATE_THRESHOLD = 0.01f; - - // NOTA BENE: This is (intentionally?) using the small angle sine approximation to test for rotation - // Plus, there is an extra 0.5 in the mix since the perpendicular between last_camera_at and getAtAxis() bisects cam_rot_change - // Thus, we're actually testing against 0.2 degrees - const F32 ROTATION_THRESHOLD = 0.1f * 2.f*F_PI/360.f; // Rotation thresh 0.2 deg, see note above - - const U8 DUP_MSGS = 1; // HACK! number of times to repeat data on motionless agent - - // Store data on last sent update so that if no changes, no send - static LLVector3 last_camera_pos_agent, - last_camera_at, - last_camera_left, - last_camera_up; - - static LLVector3 cam_center_chg, - cam_rot_chg; - - static LLQuaternion last_head_rot; - static U32 last_control_flags = 0; - static U8 last_render_state; - static U8 duplicate_count = 0; - static F32 head_rot_chg = 1.0; - static U8 last_flags; - - LLMessageSystem *msg = gMessageSystem; - LLVector3 camera_pos_agent; // local to avatar's region - U8 render_state; - - LLQuaternion body_rotation = gAgent.getFrameAgent().getQuaternion(); - LLQuaternion head_rotation = gAgent.getHeadRotation(); - - camera_pos_agent = gAgentCamera.getCameraPositionAgent(); - - render_state = gAgent.getRenderState(); - - U32 control_flag_change = 0; - U8 flag_change = 0; - - cam_center_chg = last_camera_pos_agent - camera_pos_agent; - cam_rot_chg = last_camera_at - LLViewerCamera::getInstance()->getAtAxis(); - - // If a modifier key is held down, turn off - // LBUTTON and ML_LBUTTON so that using the camera (alt-key) doesn't - // trigger a control event. - U32 control_flags = gAgent.getControlFlags(); - MASK key_mask = gKeyboard->currentMask(TRUE); - if (key_mask & MASK_ALT || key_mask & MASK_CONTROL) - { - control_flags &= ~( AGENT_CONTROL_LBUTTON_DOWN | - AGENT_CONTROL_ML_LBUTTON_DOWN ); - control_flags |= AGENT_CONTROL_LBUTTON_UP | - AGENT_CONTROL_ML_LBUTTON_UP ; - } - - control_flag_change = last_control_flags ^ control_flags; - - U8 flags = AU_FLAGS_NONE; - if (gAgent.isGroupTitleHidden()) - { - flags |= AU_FLAGS_HIDETITLE; - } - if (gAgent.getAutoPilot()) - { - flags |= AU_FLAGS_CLIENT_AUTOPILOT; - } - - flag_change = last_flags ^ flags; - - head_rot_chg = dot(last_head_rot, head_rotation); - - if (force_send || - (cam_center_chg.magVec() > TRANSLATE_THRESHOLD) || - (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT) || - (last_render_state != render_state) || - (cam_rot_chg.magVec() > ROTATION_THRESHOLD) || - control_flag_change != 0 || - flag_change != 0) - { -/* - if (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT) - { - //LL_INFOS("Messaging") << "head rot " << head_rotation << LL_ENDL; - LL_INFOS("Messaging") << "head_rot_chg = " << head_rot_chg << LL_ENDL; - } - if (cam_rot_chg.magVec() > ROTATION_THRESHOLD) - { - LL_INFOS("Messaging") << "cam rot " << cam_rot_chg.magVec() << LL_ENDL; - } - if (cam_center_chg.magVec() > TRANSLATE_THRESHOLD) - { - LL_INFOS("Messaging") << "cam center " << cam_center_chg.magVec() << LL_ENDL; - } -// if (drag_delta_chg.magVec() > TRANSLATE_THRESHOLD) -// { -// LL_INFOS("Messaging") << "drag delta " << drag_delta_chg.magVec() << LL_ENDL; -// } - if (control_flag_change) - { - LL_INFOS("Messaging") << "dcf = " << control_flag_change << LL_ENDL; - } -*/ - - duplicate_count = 0; - } - else - { - duplicate_count++; - - if (head_rot_chg < MAX_HEAD_ROT_QDOT && duplicate_count < AGENT_UPDATES_PER_SECOND) - { - // The head_rotation is sent for updating things like attached guns. - // We only trigger a new update when head_rotation deviates beyond - // some threshold from the last update, however this can break fine - // adjustments when trying to aim an attached gun, so what we do here - // (where we would normally skip sending an update when nothing has changed) - // is gradually reduce the threshold to allow a better update to - // eventually get sent... should update to within 0.5 degrees in less - // than a second. - if (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT + (MAX_HEAD_ROT_QDOT - THRESHOLD_HEAD_ROT_QDOT) * duplicate_count / AGENT_UPDATES_PER_SECOND) - { - duplicate_count = 0; - } - else - { - return; - } - } - else - { - return; - } - } - - if (duplicate_count < DUP_MSGS && !gDisconnected) - { - LLFastTimer t(FTM_AGENT_UPDATE_SEND); - // Build the message - msg->newMessageFast(_PREHASH_AgentUpdate); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addQuatFast(_PREHASH_BodyRotation, body_rotation); - msg->addQuatFast(_PREHASH_HeadRotation, head_rotation); - msg->addU8Fast(_PREHASH_State, render_state); - msg->addU8Fast(_PREHASH_Flags, flags); - -// if (camera_pos_agent.mV[VY] > 255.f) -// { -// LL_INFOS("Messaging") << "Sending camera center " << camera_pos_agent << LL_ENDL; -// } - - msg->addVector3Fast(_PREHASH_CameraCenter, camera_pos_agent); - msg->addVector3Fast(_PREHASH_CameraAtAxis, LLViewerCamera::getInstance()->getAtAxis()); - msg->addVector3Fast(_PREHASH_CameraLeftAxis, LLViewerCamera::getInstance()->getLeftAxis()); - msg->addVector3Fast(_PREHASH_CameraUpAxis, LLViewerCamera::getInstance()->getUpAxis()); - msg->addF32Fast(_PREHASH_Far, gAgentCamera.mDrawDistance); - - msg->addU32Fast(_PREHASH_ControlFlags, control_flags); - - if (gDebugClicks) - { - if (control_flags & AGENT_CONTROL_LBUTTON_DOWN) - { - LL_INFOS("Messaging") << "AgentUpdate left button down" << LL_ENDL; - } - - if (control_flags & AGENT_CONTROL_LBUTTON_UP) - { - LL_INFOS("Messaging") << "AgentUpdate left button up" << LL_ENDL; - } - } - - gAgent.enableControlFlagReset(); - - if (!send_reliable) - { - gAgent.sendMessage(); - } - else - { - gAgent.sendReliableMessage(); - } - -// LL_DEBUGS("Messaging") << "agent " << avatar_pos_agent << " cam " << camera_pos_agent << LL_ENDL; - - // Copy the old data - last_head_rot = head_rotation; - last_render_state = render_state; - last_camera_pos_agent = camera_pos_agent; - last_camera_at = LLViewerCamera::getInstance()->getAtAxis(); - last_camera_left = LLViewerCamera::getInstance()->getLeftAxis(); - last_camera_up = LLViewerCamera::getInstance()->getUpAxis(); - last_control_flags = control_flags; - last_flags = flags; - } -} - - - -// *TODO: Remove this dependency, or figure out a better way to handle -// this hack. -extern U32 gObjectBits; - -void process_object_update(LLMessageSystem *mesgsys, void **user_data) -{ - LLMemType mt(LLMemType::MTYPE_OBJECT); - // Update the data counters - if (mesgsys->getReceiveCompressedSize()) - { - gObjectBits += mesgsys->getReceiveCompressedSize() * 8; - } - else - { - gObjectBits += mesgsys->getReceiveSize() * 8; - } - - // Update the object... - gObjectList.processObjectUpdate(mesgsys, user_data, OUT_FULL); -} - -void process_compressed_object_update(LLMessageSystem *mesgsys, void **user_data) -{ - LLMemType mt(LLMemType::MTYPE_OBJECT); - // Update the data counters - if (mesgsys->getReceiveCompressedSize()) - { - gObjectBits += mesgsys->getReceiveCompressedSize() * 8; - } - else - { - gObjectBits += mesgsys->getReceiveSize() * 8; - } - - // Update the object... - gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_FULL_COMPRESSED); -} - -void process_cached_object_update(LLMessageSystem *mesgsys, void **user_data) -{ - LLMemType mt(LLMemType::MTYPE_OBJECT); - // Update the data counters - if (mesgsys->getReceiveCompressedSize()) - { - gObjectBits += mesgsys->getReceiveCompressedSize() * 8; - } - else - { - gObjectBits += mesgsys->getReceiveSize() * 8; - } - - // Update the object... - gObjectList.processCachedObjectUpdate(mesgsys, user_data, OUT_FULL_CACHED); -} - - -void process_terse_object_update_improved(LLMessageSystem *mesgsys, void **user_data) -{ - LLMemType mt(LLMemType::MTYPE_OBJECT); - if (mesgsys->getReceiveCompressedSize()) - { - gObjectBits += mesgsys->getReceiveCompressedSize() * 8; - } - else - { - gObjectBits += mesgsys->getReceiveSize() * 8; - } - - gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_TERSE_IMPROVED); -} - -static LLFastTimer::DeclareTimer FTM_PROCESS_OBJECTS("Process Objects"); - - -void process_kill_object(LLMessageSystem *mesgsys, void **user_data) -{ - LLFastTimer t(FTM_PROCESS_OBJECTS); - - LLUUID id; - U32 local_id; - S32 i; - S32 num_objects; - - num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData); - - for (i = 0; i < num_objects; i++) - { - mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i); - - LLViewerObjectList::getUUIDFromLocal(id, - local_id, - gMessageSystem->getSenderIP(), - gMessageSystem->getSenderPort()); - if (id == LLUUID::null) - { - LL_DEBUGS("Messaging") << "Unknown kill for local " << local_id << LL_ENDL; - gObjectList.mNumUnknownKills++; - continue; - } - else - { - LL_DEBUGS("Messaging") << "Kill message for local " << local_id << LL_ENDL; - } - - LLSelectMgr::getInstance()->removeObjectFromSelections(id); - - // ...don't kill the avatar - if (!(id == gAgentID)) - { - LLViewerObject *objectp = gObjectList.findObject(id); - if (objectp) - { - // Display green bubble on kill - if ( gShowObjectUpdates ) - { - LLViewerObject* newobject; - newobject = gObjectList.createObjectViewer(LL_PCODE_LEGACY_TEXT_BUBBLE, objectp->getRegion()); - - LLVOTextBubble* bubble = (LLVOTextBubble*) newobject; - - bubble->mColor.setVec(0.f, 1.f, 0.f, 1.f); - bubble->setScale( 2.0f * bubble->getScale() ); - bubble->setPositionGlobal(objectp->getPositionGlobal()); - gPipeline.addObject(bubble); - } - - // Do the kill - gObjectList.killObject(objectp); - } - else - { - LL_WARNS("Messaging") << "Object in UUID lookup, but not on object list in kill!" << LL_ENDL; - gObjectList.mNumUnknownKills++; - } - } - } -} - -void process_time_synch(LLMessageSystem *mesgsys, void **user_data) -{ - LLVector3 sun_direction; - LLVector3 sun_ang_velocity; - F32 phase; - U64 space_time_usec; - - U32 seconds_per_day; - U32 seconds_per_year; - - // "SimulatorViewerTimeMessage" - mesgsys->getU64Fast(_PREHASH_TimeInfo, _PREHASH_UsecSinceStart, space_time_usec); - mesgsys->getU32Fast(_PREHASH_TimeInfo, _PREHASH_SecPerDay, seconds_per_day); - mesgsys->getU32Fast(_PREHASH_TimeInfo, _PREHASH_SecPerYear, seconds_per_year); - - // This should eventually be moved to an "UpdateHeavenlyBodies" message - mesgsys->getF32Fast(_PREHASH_TimeInfo, _PREHASH_SunPhase, phase); - mesgsys->getVector3Fast(_PREHASH_TimeInfo, _PREHASH_SunDirection, sun_direction); - mesgsys->getVector3Fast(_PREHASH_TimeInfo, _PREHASH_SunAngVelocity, sun_ang_velocity); - - LLWorld::getInstance()->setSpaceTimeUSec(space_time_usec); - - //LL_DEBUGS("Messaging") << "time_synch() - " << sun_direction << ", " << sun_ang_velocity - // << ", " << phase << LL_ENDL; - - gSky.setSunPhase(phase); - gSky.setSunTargetDirection(sun_direction, sun_ang_velocity); - if (!gNoRender && !(gSavedSettings.getBOOL("SkyOverrideSimSunPosition") || gSky.getOverrideSun())) - { - gSky.setSunDirection(sun_direction, sun_ang_velocity); - } -} - -void process_sound_trigger(LLMessageSystem *msg, void **) -{ - if (!gAudiop) return; - - U64 region_handle = 0; - F32 gain = 0; - LLUUID sound_id; - LLUUID owner_id; - LLUUID object_id; - LLUUID parent_id; - LLVector3 pos_local; - - msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_SoundID, sound_id); - msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_OwnerID, owner_id); - msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_ObjectID, object_id); - msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_ParentID, parent_id); - msg->getU64Fast(_PREHASH_SoundData, _PREHASH_Handle, region_handle); - msg->getVector3Fast(_PREHASH_SoundData, _PREHASH_Position, pos_local); - msg->getF32Fast(_PREHASH_SoundData, _PREHASH_Gain, gain); - - // adjust sound location to true global coords - LLVector3d pos_global = from_region_handle(region_handle); - pos_global.mdV[VX] += pos_local.mV[VX]; - pos_global.mdV[VY] += pos_local.mV[VY]; - pos_global.mdV[VZ] += pos_local.mV[VZ]; - - // Don't play a trigger sound if you can't hear it due - // to parcel "local audio only" settings. - if (!LLViewerParcelMgr::getInstance()->canHearSound(pos_global)) return; - - // Don't play sounds triggered by someone you muted. - if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return; - - // Don't play sounds from an object you muted - if (LLMuteList::getInstance()->isMuted(object_id)) return; - - // Don't play sounds from an object whose parent you muted - if (parent_id.notNull() - && LLMuteList::getInstance()->isMuted(parent_id)) - { - return; - } - - // Don't play sounds from a region with maturity above current agent maturity - if( !gAgent.canAccessMaturityInRegion( region_handle ) ) - { - return; - } - - gAudiop->triggerSound(sound_id, owner_id, gain, LLAudioEngine::AUDIO_TYPE_SFX, pos_global); -} - -void process_preload_sound(LLMessageSystem *msg, void **user_data) -{ - if (!gAudiop) - { - return; - } - - LLUUID sound_id; - LLUUID object_id; - LLUUID owner_id; - - msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_SoundID, sound_id); - msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_id); - msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_OwnerID, owner_id); - - LLViewerObject *objectp = gObjectList.findObject(object_id); - if (!objectp) return; - - if (LLMuteList::getInstance()->isMuted(object_id)) return; - if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return; - - LLAudioSource *sourcep = objectp->getAudioSource(owner_id); - if (!sourcep) return; - - LLAudioData *datap = gAudiop->getAudioData(sound_id); - - // Note that I don't actually do any loading of the - // audio data into a buffer at this point, as it won't actually - // help us out. - - // Don't play sounds from a region with maturity above current agent maturity - LLVector3d pos_global = objectp->getPositionGlobal(); - if (gAgent.canAccessMaturityAtGlobal(pos_global)) - { - // Add audioData starts a transfer internally. - sourcep->addAudioData(datap, FALSE); -} -} - -void process_attached_sound(LLMessageSystem *msg, void **user_data) -{ - F32 gain = 0; - LLUUID sound_id; - LLUUID object_id; - LLUUID owner_id; - U8 flags; - - msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_SoundID, sound_id); - msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_id); - msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_OwnerID, owner_id); - msg->getF32Fast(_PREHASH_DataBlock, _PREHASH_Gain, gain); - msg->getU8Fast(_PREHASH_DataBlock, _PREHASH_Flags, flags); - - LLViewerObject *objectp = gObjectList.findObject(object_id); - if (!objectp) - { - // we don't know about this object, just bail - return; - } - - if (LLMuteList::getInstance()->isMuted(object_id)) return; - - if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return; - - - // Don't play sounds from a region with maturity above current agent maturity - LLVector3d pos = objectp->getPositionGlobal(); - if( !gAgent.canAccessMaturityAtGlobal(pos) ) - { - return; - } - - objectp->setAttachedSound(sound_id, owner_id, gain, flags); -} - - -void process_attached_sound_gain_change(LLMessageSystem *mesgsys, void **user_data) -{ - F32 gain = 0; - LLUUID object_guid; - LLViewerObject *objectp = NULL; - - mesgsys->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_guid); - - if (!((objectp = gObjectList.findObject(object_guid)))) - { - // we don't know about this object, just bail - return; - } - - mesgsys->getF32Fast(_PREHASH_DataBlock, _PREHASH_Gain, gain); - - objectp->adjustAudioGain(gain); -} - - -void process_health_message(LLMessageSystem *mesgsys, void **user_data) -{ - F32 health; - - mesgsys->getF32Fast(_PREHASH_HealthData, _PREHASH_Health, health); - - if (gStatusBar) - { - gStatusBar->setHealth((S32)health); - } -} - - -void process_sim_stats(LLMessageSystem *msg, void **user_data) -{ - S32 count = msg->getNumberOfBlocks("Stat"); - for (S32 i = 0; i < count; ++i) - { - U32 stat_id; - F32 stat_value; - msg->getU32("Stat", "StatID", stat_id, i); - msg->getF32("Stat", "StatValue", stat_value, i); - switch (stat_id) - { - case LL_SIM_STAT_TIME_DILATION: - LLViewerStats::getInstance()->mSimTimeDilation.addValue(stat_value); - break; - case LL_SIM_STAT_FPS: - LLViewerStats::getInstance()->mSimFPS.addValue(stat_value); - break; - case LL_SIM_STAT_PHYSFPS: - LLViewerStats::getInstance()->mSimPhysicsFPS.addValue(stat_value); - break; - case LL_SIM_STAT_AGENTUPS: - LLViewerStats::getInstance()->mSimAgentUPS.addValue(stat_value); - break; - case LL_SIM_STAT_FRAMEMS: - LLViewerStats::getInstance()->mSimFrameMsec.addValue(stat_value); - break; - case LL_SIM_STAT_NETMS: - LLViewerStats::getInstance()->mSimNetMsec.addValue(stat_value); - break; - case LL_SIM_STAT_SIMOTHERMS: - LLViewerStats::getInstance()->mSimSimOtherMsec.addValue(stat_value); - break; - case LL_SIM_STAT_SIMPHYSICSMS: - LLViewerStats::getInstance()->mSimSimPhysicsMsec.addValue(stat_value); - break; - case LL_SIM_STAT_AGENTMS: - LLViewerStats::getInstance()->mSimAgentMsec.addValue(stat_value); - break; - case LL_SIM_STAT_IMAGESMS: - LLViewerStats::getInstance()->mSimImagesMsec.addValue(stat_value); - break; - case LL_SIM_STAT_SCRIPTMS: - LLViewerStats::getInstance()->mSimScriptMsec.addValue(stat_value); - break; - case LL_SIM_STAT_NUMTASKS: - LLViewerStats::getInstance()->mSimObjects.addValue(stat_value); - break; - case LL_SIM_STAT_NUMTASKSACTIVE: - LLViewerStats::getInstance()->mSimActiveObjects.addValue(stat_value); - break; - case LL_SIM_STAT_NUMAGENTMAIN: - LLViewerStats::getInstance()->mSimMainAgents.addValue(stat_value); - break; - case LL_SIM_STAT_NUMAGENTCHILD: - LLViewerStats::getInstance()->mSimChildAgents.addValue(stat_value); - break; - case LL_SIM_STAT_NUMSCRIPTSACTIVE: - LLViewerStats::getInstance()->mSimActiveScripts.addValue(stat_value); - break; - case LL_SIM_STAT_SCRIPT_EPS: - LLViewerStats::getInstance()->mSimScriptEPS.addValue(stat_value); - break; - case LL_SIM_STAT_INPPS: - LLViewerStats::getInstance()->mSimInPPS.addValue(stat_value); - break; - case LL_SIM_STAT_OUTPPS: - LLViewerStats::getInstance()->mSimOutPPS.addValue(stat_value); - break; - case LL_SIM_STAT_PENDING_DOWNLOADS: - LLViewerStats::getInstance()->mSimPendingDownloads.addValue(stat_value); - break; - case LL_SIM_STAT_PENDING_UPLOADS: - LLViewerStats::getInstance()->mSimPendingUploads.addValue(stat_value); - break; - case LL_SIM_STAT_PENDING_LOCAL_UPLOADS: - LLViewerStats::getInstance()->mSimPendingLocalUploads.addValue(stat_value); - break; - case LL_SIM_STAT_TOTAL_UNACKED_BYTES: - LLViewerStats::getInstance()->mSimTotalUnackedBytes.addValue(stat_value / 1024.f); - break; - case LL_SIM_STAT_PHYSICS_PINNED_TASKS: - LLViewerStats::getInstance()->mPhysicsPinnedTasks.addValue(stat_value); - break; - case LL_SIM_STAT_PHYSICS_LOD_TASKS: - LLViewerStats::getInstance()->mPhysicsLODTasks.addValue(stat_value); - break; - case LL_SIM_STAT_SIMPHYSICSSTEPMS: - LLViewerStats::getInstance()->mSimSimPhysicsStepMsec.addValue(stat_value); - break; - case LL_SIM_STAT_SIMPHYSICSSHAPEMS: - LLViewerStats::getInstance()->mSimSimPhysicsShapeUpdateMsec.addValue(stat_value); - break; - case LL_SIM_STAT_SIMPHYSICSOTHERMS: - LLViewerStats::getInstance()->mSimSimPhysicsOtherMsec.addValue(stat_value); - break; - case LL_SIM_STAT_SIMPHYSICSMEMORY: - LLViewerStats::getInstance()->mPhysicsMemoryAllocated.addValue(stat_value); - break; - case LL_SIM_STAT_SIMSPARETIME: - LLViewerStats::getInstance()->mSimSpareMsec.addValue(stat_value); - break; - case LL_SIM_STAT_SIMSLEEPTIME: - LLViewerStats::getInstance()->mSimSleepMsec.addValue(stat_value); - break; - case LL_SIM_STAT_IOPUMPTIME: - LLViewerStats::getInstance()->mSimPumpIOMsec.addValue(stat_value); - break; - default: - // Used to be a commented out warning. - LL_DEBUGS("Messaging") << "Unknown stat id" << stat_id << LL_ENDL; - break; - } - } - - /* - msg->getF32Fast(_PREHASH_Statistics, _PREHASH_PhysicsTimeDilation, time_dilation); - LLViewerStats::getInstance()->mSimTDStat.addValue(time_dilation); - - // Process information - // { CpuUsage F32 } - // { SimMemTotal F32 } - // { SimMemRSS F32 } - // { ProcessUptime F32 } - F32 cpu_usage; - F32 sim_mem_total; - F32 sim_mem_rss; - F32 process_uptime; - msg->getF32Fast(_PREHASH_Statistics, _PREHASH_CpuUsage, cpu_usage); - msg->getF32Fast(_PREHASH_Statistics, _PREHASH_SimMemTotal, sim_mem_total); - msg->getF32Fast(_PREHASH_Statistics, _PREHASH_SimMemRSS, sim_mem_rss); - msg->getF32Fast(_PREHASH_Statistics, _PREHASH_ProcessUptime, process_uptime); - LLViewerStats::getInstance()->mSimCPUUsageStat.addValue(cpu_usage); - LLViewerStats::getInstance()->mSimMemTotalStat.addValue(sim_mem_total); - LLViewerStats::getInstance()->mSimMemRSSStat.addValue(sim_mem_rss); - */ - - // - // Various hacks that aren't statistics, but are being handled here. - // - U32 max_tasks_per_region; - U32 region_flags; - msg->getU32("Region", "ObjectCapacity", max_tasks_per_region); - msg->getU32("Region", "RegionFlags", region_flags); - - LLViewerRegion* regionp = gAgent.getRegion(); - if (regionp) - { - BOOL was_flying = gAgent.getFlying(); - regionp->setRegionFlags(region_flags); - regionp->setMaxTasks(max_tasks_per_region); - // HACK: This makes agents drop from the sky if the region is - // set to no fly while people are still in the sim. - if (was_flying && regionp->getBlockFly()) - { - gAgent.setFlying(gAgent.canFly()); - } - } -} - - - -void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data) -{ - LLUUID animation_id; - LLUUID uuid; - S32 anim_sequence_id; - LLVOAvatar *avatarp; - - mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); - - //clear animation flags - avatarp = (LLVOAvatar *)gObjectList.findObject(uuid); - - if (!avatarp) - { - // no agent by this ID...error? - LL_WARNS("Messaging") << "Received animation state for unknown avatar" << uuid << LL_ENDL; - return; - } - - S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList); - S32 num_source_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationSourceList); - - avatarp->mSignaledAnimations.clear(); - - if (avatarp->isSelf()) - { - LLUUID object_id; - - for( S32 i = 0; i < num_blocks; i++ ) - { - mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i); - mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i); - - LL_DEBUGS("Messaging") << "Anim sequence ID: " << anim_sequence_id << LL_ENDL; - - avatarp->mSignaledAnimations[animation_id] = anim_sequence_id; - - // *HACK: Disabling flying mode if it has been enabled shortly before the agent - // stand up animation is signaled. In this case we don't get a signal to start - // flying animation from server, the AGENT_CONTROL_FLY flag remains set but the - // avatar does not play flying animation, so we switch flying mode off. - // See LLAgent::setFlying(). This may cause "Stop Flying" button to blink. - // See EXT-2781. - if (animation_id == ANIM_AGENT_STANDUP && gAgent.getFlying()) - { - gAgent.setFlying(FALSE); - } - - if (i < num_source_blocks) - { - mesgsys->getUUIDFast(_PREHASH_AnimationSourceList, _PREHASH_ObjectID, object_id, i); - - LLViewerObject* object = gObjectList.findObject(object_id); - if (object) - { - object->mFlags |= FLAGS_ANIM_SOURCE; - - BOOL anim_found = FALSE; - LLVOAvatar::AnimSourceIterator anim_it = avatarp->mAnimationSources.find(object_id); - for (;anim_it != avatarp->mAnimationSources.end(); ++anim_it) - { - if (anim_it->second == animation_id) - { - anim_found = TRUE; - break; - } - } - - if (!anim_found) - { - avatarp->mAnimationSources.insert(LLVOAvatar::AnimationSourceMap::value_type(object_id, animation_id)); - } - } - } - } - } - else - { - for( S32 i = 0; i < num_blocks; i++ ) - { - mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i); - mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i); - avatarp->mSignaledAnimations[animation_id] = anim_sequence_id; - } - } - - if (num_blocks) - { - avatarp->processAnimationStateChanges(); - } -} - -void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data) -{ - LLUUID uuid; - mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid); - - LLVOAvatar* avatarp = (LLVOAvatar *)gObjectList.findObject(uuid); - if (avatarp) - { - avatarp->processAvatarAppearance( mesgsys ); - } - else - { - LL_WARNS("Messaging") << "avatar_appearance sent for unknown avatar " << uuid << LL_ENDL; - } -} - -void process_camera_constraint(LLMessageSystem *mesgsys, void **user_data) -{ - LLVector4 cameraCollidePlane; - mesgsys->getVector4Fast(_PREHASH_CameraCollidePlane, _PREHASH_Plane, cameraCollidePlane); - - gAgentCamera.setCameraCollidePlane(cameraCollidePlane); -} - -void near_sit_object(BOOL success, void *data) -{ - if (success) - { - // Send message to sit on object - gMessageSystem->newMessageFast(_PREHASH_AgentSit); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gAgent.sendReliableMessage(); - } -} - -void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data) -{ - LLVector3 sitPosition; - LLQuaternion sitRotation; - LLUUID sitObjectID; - BOOL use_autopilot; - mesgsys->getUUIDFast(_PREHASH_SitObject, _PREHASH_ID, sitObjectID); - mesgsys->getBOOLFast(_PREHASH_SitTransform, _PREHASH_AutoPilot, use_autopilot); - mesgsys->getVector3Fast(_PREHASH_SitTransform, _PREHASH_SitPosition, sitPosition); - mesgsys->getQuatFast(_PREHASH_SitTransform, _PREHASH_SitRotation, sitRotation); - LLVector3 camera_eye; - mesgsys->getVector3Fast(_PREHASH_SitTransform, _PREHASH_CameraEyeOffset, camera_eye); - LLVector3 camera_at; - mesgsys->getVector3Fast(_PREHASH_SitTransform, _PREHASH_CameraAtOffset, camera_at); - BOOL force_mouselook; - mesgsys->getBOOLFast(_PREHASH_SitTransform, _PREHASH_ForceMouselook, force_mouselook); - - if (isAgentAvatarValid() && dist_vec_squared(camera_eye, camera_at) > 0.0001f) - { - gAgentCamera.setSitCamera(sitObjectID, camera_eye, camera_at); - } - - gAgentCamera.setForceMouselook(force_mouselook); - // Forcing turning off flying here to prevent flying after pressing "Stand" - // to stand up from an object. See EXT-1655. - gAgent.setFlying(FALSE); - - LLViewerObject* object = gObjectList.findObject(sitObjectID); - if (object) - { - LLVector3 sit_spot = object->getPositionAgent() + (sitPosition * object->getRotation()); - if (!use_autopilot || isAgentAvatarValid() && gAgentAvatarp->isSitting() && gAgentAvatarp->getRoot() == object->getRoot()) - { - //we're already sitting on this object, so don't autopilot - } - else - { - gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(sit_spot), "Sit", &sitRotation, near_sit_object, NULL, 0.5f); - } - } - else - { - LL_WARNS("Messaging") << "Received sit approval for unknown object " << sitObjectID << LL_ENDL; - } -} - -void process_clear_follow_cam_properties(LLMessageSystem *mesgsys, void **user_data) -{ - LLUUID source_id; - - mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, source_id); - - LLFollowCamMgr::removeFollowCamParams(source_id); -} - -void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_data) -{ - S32 type; - F32 value; - bool settingPosition = false; - bool settingFocus = false; - bool settingFocusOffset = false; - LLVector3 position; - LLVector3 focus; - LLVector3 focus_offset; - - LLUUID source_id; - - mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, source_id); - - LLViewerObject* objectp = gObjectList.findObject(source_id); - if (objectp) - { - objectp->mFlags |= FLAGS_CAMERA_SOURCE; - } - - S32 num_objects = mesgsys->getNumberOfBlocks("CameraProperty"); - for (S32 block_index = 0; block_index < num_objects; block_index++) - { - mesgsys->getS32("CameraProperty", "Type", type, block_index); - mesgsys->getF32("CameraProperty", "Value", value, block_index); - switch(type) - { - case FOLLOWCAM_PITCH: - LLFollowCamMgr::setPitch(source_id, value); - break; - case FOLLOWCAM_FOCUS_OFFSET_X: - focus_offset.mV[VX] = value; - settingFocusOffset = true; - break; - case FOLLOWCAM_FOCUS_OFFSET_Y: - focus_offset.mV[VY] = value; - settingFocusOffset = true; - break; - case FOLLOWCAM_FOCUS_OFFSET_Z: - focus_offset.mV[VZ] = value; - settingFocusOffset = true; - break; - case FOLLOWCAM_POSITION_LAG: - LLFollowCamMgr::setPositionLag(source_id, value); - break; - case FOLLOWCAM_FOCUS_LAG: - LLFollowCamMgr::setFocusLag(source_id, value); - break; - case FOLLOWCAM_DISTANCE: - LLFollowCamMgr::setDistance(source_id, value); - break; - case FOLLOWCAM_BEHINDNESS_ANGLE: - LLFollowCamMgr::setBehindnessAngle(source_id, value); - break; - case FOLLOWCAM_BEHINDNESS_LAG: - LLFollowCamMgr::setBehindnessLag(source_id, value); - break; - case FOLLOWCAM_POSITION_THRESHOLD: - LLFollowCamMgr::setPositionThreshold(source_id, value); - break; - case FOLLOWCAM_FOCUS_THRESHOLD: - LLFollowCamMgr::setFocusThreshold(source_id, value); - break; - case FOLLOWCAM_ACTIVE: - //if 1, set using followcam,. - LLFollowCamMgr::setCameraActive(source_id, value != 0.f); - break; - case FOLLOWCAM_POSITION_X: - settingPosition = true; - position.mV[ 0 ] = value; - break; - case FOLLOWCAM_POSITION_Y: - settingPosition = true; - position.mV[ 1 ] = value; - break; - case FOLLOWCAM_POSITION_Z: - settingPosition = true; - position.mV[ 2 ] = value; - break; - case FOLLOWCAM_FOCUS_X: - settingFocus = true; - focus.mV[ 0 ] = value; - break; - case FOLLOWCAM_FOCUS_Y: - settingFocus = true; - focus.mV[ 1 ] = value; - break; - case FOLLOWCAM_FOCUS_Z: - settingFocus = true; - focus.mV[ 2 ] = value; - break; - case FOLLOWCAM_POSITION_LOCKED: - LLFollowCamMgr::setPositionLocked(source_id, value != 0.f); - break; - case FOLLOWCAM_FOCUS_LOCKED: - LLFollowCamMgr::setFocusLocked(source_id, value != 0.f); - break; - - default: - break; - } - } - - if ( settingPosition ) - { - LLFollowCamMgr::setPosition(source_id, position); - } - if ( settingFocus ) - { - LLFollowCamMgr::setFocus(source_id, focus); - } - if ( settingFocusOffset ) - { - LLFollowCamMgr::setFocusOffset(source_id, focus_offset); - } -} -//end Ventrella - - -// Culled from newsim lltask.cpp -void process_name_value(LLMessageSystem *mesgsys, void **user_data) -{ - std::string temp_str; - LLUUID id; - S32 i, num_blocks; - - mesgsys->getUUIDFast(_PREHASH_TaskData, _PREHASH_ID, id); - - LLViewerObject* object = gObjectList.findObject(id); - - if (object) - { - num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_NameValueData); - for (i = 0; i < num_blocks; i++) - { - mesgsys->getStringFast(_PREHASH_NameValueData, _PREHASH_NVPair, temp_str, i); - LL_INFOS("Messaging") << "Added to object Name Value: " << temp_str << LL_ENDL; - object->addNVPair(temp_str); - } - } - else - { - LL_INFOS("Messaging") << "Can't find object " << id << " to add name value pair" << LL_ENDL; - } -} - -void process_remove_name_value(LLMessageSystem *mesgsys, void **user_data) -{ - std::string temp_str; - LLUUID id; - S32 i, num_blocks; - - mesgsys->getUUIDFast(_PREHASH_TaskData, _PREHASH_ID, id); - - LLViewerObject* object = gObjectList.findObject(id); - - if (object) - { - num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_NameValueData); - for (i = 0; i < num_blocks; i++) - { - mesgsys->getStringFast(_PREHASH_NameValueData, _PREHASH_NVPair, temp_str, i); - LL_INFOS("Messaging") << "Removed from object Name Value: " << temp_str << LL_ENDL; - object->removeNVPair(temp_str); - } - } - else - { - LL_INFOS("Messaging") << "Can't find object " << id << " to remove name value pair" << LL_ENDL; - } -} - -void process_kick_user(LLMessageSystem *msg, void** /*user_data*/) -{ - std::string message; - - msg->getStringFast(_PREHASH_UserInfo, _PREHASH_Reason, message); - - LLAppViewer::instance()->forceDisconnect(message); -} - - -/* -void process_user_list_reply(LLMessageSystem *msg, void **user_data) -{ - LLUserList::processUserListReply(msg, user_data); - return; - char firstname[MAX_STRING+1]; - char lastname[MAX_STRING+1]; - U8 status; - S32 user_count; - - user_count = msg->getNumberOfBlocks("UserBlock"); - - for (S32 i = 0; i < user_count; i++) - { - msg->getData("UserBlock", i, "FirstName", firstname); - msg->getData("UserBlock", i, "LastName", lastname); - msg->getData("UserBlock", i, "Status", &status); - - if (status & 0x01) - { - dialog_friends_add_friend(buffer, TRUE); - } - else - { - dialog_friends_add_friend(buffer, FALSE); - } - } - - dialog_friends_done_adding(); -} -*/ - -// this is not handled in processUpdateMessage -/* -void process_time_dilation(LLMessageSystem *msg, void **user_data) -{ - // get the time_dilation - U16 foo; - msg->getData("TimeDilation", "TimeDilation", &foo); - F32 time_dilation = ((F32) foo) / 65535.f; - - // get the pointer to the right region - U32 ip = msg->getSenderIP(); - U32 port = msg->getSenderPort(); - LLViewerRegion *regionp = LLWorld::getInstance()->getRegion(ip, port); - if (regionp) - { - regionp->setTimeDilation(time_dilation); - } -} -*/ - - -void process_money_balance_reply( LLMessageSystem* msg, void** ) -{ - S32 balance = 0; - S32 credit = 0; - S32 committed = 0; - std::string desc; - LLUUID tid; - - msg->getUUID("MoneyData", "TransactionID", tid); - msg->getS32("MoneyData", "MoneyBalance", balance); - msg->getS32("MoneyData", "SquareMetersCredit", credit); - msg->getS32("MoneyData", "SquareMetersCommitted", committed); - msg->getStringFast(_PREHASH_MoneyData, _PREHASH_Description, desc); - LL_INFOS("Messaging") << "L$, credit, committed: " << balance << " " << credit << " " - << committed << LL_ENDL; - - if (gStatusBar) - { - gStatusBar->setBalance(balance); - gStatusBar->setLandCredit(credit); - gStatusBar->setLandCommitted(committed); - } - - if (desc.empty() - || !gSavedSettings.getBOOL("NotifyMoneyChange")) - { - // ...nothing to display - return; - } - - // Suppress duplicate messages about the same transaction - static std::deque<LLUUID> recent; - if (std::find(recent.rbegin(), recent.rend(), tid) != recent.rend()) - { - return; - } - - // Once the 'recent' container gets large enough, chop some - // off the beginning. - const U32 MAX_LOOKBACK = 30; - const S32 POP_FRONT_SIZE = 12; - if(recent.size() > MAX_LOOKBACK) - { - LL_DEBUGS("Messaging") << "Removing oldest transaction records" << LL_ENDL; - recent.erase(recent.begin(), recent.begin() + POP_FRONT_SIZE); - } - //LL_DEBUGS("Messaging") << "Pushing back transaction " << tid << LL_ENDL; - recent.push_back(tid); - - if (msg->has("TransactionInfo")) - { - // ...message has extended info for localization - process_money_balance_reply_extended(msg); - } - else - { - // Only old dev grids will not supply the TransactionInfo block, - // so we can just use the hard-coded English string. - LLSD args; - args["MESSAGE"] = desc; - LLNotificationsUtil::add("SystemMessage", args); - } -} - -static std::string reason_from_transaction_type(S32 transaction_type, - const std::string& item_desc) -{ - // *NOTE: The keys for the reason strings are unusual because - // an earlier version of the code used English language strings - // extracted from hard-coded server English descriptions. - // Keeping them so we don't have to re-localize them. - switch (transaction_type) - { - case TRANS_OBJECT_SALE: - { - LLStringUtil::format_map_t arg; - arg["ITEM"] = item_desc; - return LLTrans::getString("for item", arg); - } - case TRANS_LAND_SALE: - return LLTrans::getString("for a parcel of land"); - - case TRANS_LAND_PASS_SALE: - return LLTrans::getString("for a land access pass"); - - case TRANS_GROUP_LAND_DEED: - return LLTrans::getString("for deeding land"); - - case TRANS_GROUP_CREATE: - return LLTrans::getString("to create a group"); - - case TRANS_GROUP_JOIN: - return LLTrans::getString("to join a group"); - - case TRANS_UPLOAD_CHARGE: - return LLTrans::getString("to upload"); - - case TRANS_CLASSIFIED_CHARGE: - return LLTrans::getString("to publish a classified ad"); - - // These have no reason to display, but are expected and should not - // generate warnings - case TRANS_GIFT: - case TRANS_PAY_OBJECT: - case TRANS_OBJECT_PAYS: - return std::string(); - - default: - llwarns << "Unknown transaction type " - << transaction_type << llendl; - return std::string(); - } -} - -static void money_balance_group_notify(const LLUUID& group_id, - const std::string& name, - bool is_group, - std::string notification, - LLSD args, - LLSD payload) -{ - // Message uses name SLURLs, don't actually have to substitute in - // the name. We're just making sure it's available. - // Notification is either PaymentReceived or PaymentSent - LLNotificationsUtil::add(notification, args, payload); -} - -static void money_balance_avatar_notify(const LLUUID& agent_id, - const LLAvatarName& av_name, - std::string notification, - LLSD args, - LLSD payload) -{ - // Message uses name SLURLs, don't actually have to substitute in - // the name. We're just making sure it's available. - // Notification is either PaymentReceived or PaymentSent - LLNotificationsUtil::add(notification, args, payload); -} - -static void process_money_balance_reply_extended(LLMessageSystem* msg) -{ - // Added in server 1.40 and viewer 2.1, support for localization - // and agent ids for name lookup. - S32 transaction_type = 0; - LLUUID source_id; - BOOL is_source_group = FALSE; - LLUUID dest_id; - BOOL is_dest_group = FALSE; - S32 amount = 0; - std::string item_description; - - msg->getS32("TransactionInfo", "TransactionType", transaction_type); - msg->getUUID("TransactionInfo", "SourceID", source_id); - msg->getBOOL("TransactionInfo", "IsSourceGroup", is_source_group); - msg->getUUID("TransactionInfo", "DestID", dest_id); - msg->getBOOL("TransactionInfo", "IsDestGroup", is_dest_group); - msg->getS32("TransactionInfo", "Amount", amount); - msg->getString("TransactionInfo", "ItemDescription", item_description); - LL_INFOS("Money") << "MoneyBalanceReply source " << source_id - << " dest " << dest_id - << " type " << transaction_type - << " item " << item_description << LL_ENDL; - - if (source_id.isNull() && dest_id.isNull()) - { - // this is a pure balance update, no notification required - return; - } - - std::string source_slurl; - if (is_source_group) - { - source_slurl = - LLSLURL( "group", source_id, "inspect").getSLURLString(); - } - else - { - source_slurl = - LLSLURL( "agent", source_id, "completename").getSLURLString(); - } - - std::string dest_slurl; - if (is_dest_group) - { - dest_slurl = - LLSLURL( "group", dest_id, "inspect").getSLURLString(); - } - else - { - dest_slurl = - LLSLURL( "agent", dest_id, "completename").getSLURLString(); - } - - std::string reason = - reason_from_transaction_type(transaction_type, item_description); - - LLStringUtil::format_map_t args; - args["REASON"] = reason; // could be empty - args["AMOUNT"] = llformat("%d", amount); - - // Need to delay until name looked up, so need to know whether or not - // is group - bool is_name_group = false; - LLUUID name_id; - std::string message; - std::string notification; - LLSD final_args; - LLSD payload; - - bool you_paid_someone = (source_id == gAgentID); - if (you_paid_someone) - { - args["NAME"] = dest_slurl; - is_name_group = is_dest_group; - name_id = dest_id; - if (!reason.empty()) - { - if (dest_id.notNull()) - { - message = LLTrans::getString("you_paid_ldollars", args); - } - else - { - // transaction fee to the system, eg, to create a group - message = LLTrans::getString("you_paid_ldollars_no_name", args); - } - } - else - { - if (dest_id.notNull()) - { - message = LLTrans::getString("you_paid_ldollars_no_reason", args); - } - else - { - // no target, no reason, you just paid money - message = LLTrans::getString("you_paid_ldollars_no_info", args); - } - } - final_args["MESSAGE"] = message; - notification = "PaymentSent"; - } - else { - // ...someone paid you - args["NAME"] = source_slurl; - is_name_group = is_source_group; - name_id = source_id; - if (!reason.empty()) - { - message = LLTrans::getString("paid_you_ldollars", args); - } - else { - message = LLTrans::getString("paid_you_ldollars_no_reason", args); - } - final_args["MESSAGE"] = message; - - // make notification loggable - payload["from_id"] = source_id; - notification = "PaymentReceived"; - } - - // Despite using SLURLs, wait until the name is available before - // showing the notification, otherwise the UI layout is strange and - // the user sees a "Loading..." message - if (is_name_group) - { - gCacheName->getGroup(name_id, - boost::bind(&money_balance_group_notify, - _1, _2, _3, - notification, final_args, payload)); - } - else { - LLAvatarNameCache::get(name_id, - boost::bind(&money_balance_avatar_notify, - _1, _2, - notification, final_args, payload)); - } -} - - - -bool handle_special_notification_callback(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - if (0 == option) - { - // set the preference to the maturity of the region we're calling - int preferredMaturity = notification["payload"]["_region_access"].asInteger(); - gSavedSettings.setU32("PreferredMaturity", preferredMaturity); - gAgent.sendMaturityPreferenceToServer(preferredMaturity); - - // notify user that the maturity preference has been changed - LLSD args; - args["RATING"] = LLViewerRegion::accessToString(preferredMaturity); - LLNotificationsUtil::add("PreferredMaturityChanged", args); - } - - return false; -} - -// some of the server notifications need special handling. This is where we do that. -bool handle_special_notification(std::string notificationID, LLSD& llsdBlock) -{ - int regionAccess = llsdBlock["_region_access"].asInteger(); - llsdBlock["REGIONMATURITY"] = LLViewerRegion::accessToString(regionAccess); - - // we're going to throw the LLSD in there in case anyone ever wants to use it - LLNotificationsUtil::add(notificationID+"_Notify", llsdBlock); - - if (regionAccess == SIM_ACCESS_MATURE) - { - if (gAgent.isTeen()) - { - LLNotificationsUtil::add(notificationID+"_KB", llsdBlock); - return true; - } - else if (gAgent.prefersPG()) - { - LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_special_notification_callback); - return true; - } - } - else if (regionAccess == SIM_ACCESS_ADULT) - { - if (!gAgent.isAdult()) - { - LLNotificationsUtil::add(notificationID+"_KB", llsdBlock); - return true; - } - else if (gAgent.prefersPG() || gAgent.prefersMature()) - { - LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_special_notification_callback); - return true; - } - } - return false; -} - -bool attempt_standard_notification(LLMessageSystem* msgsystem) -{ - // if we have additional alert data - if (msgsystem->has(_PREHASH_AlertInfo) && msgsystem->getNumberOfBlocksFast(_PREHASH_AlertInfo) > 0) - { - // notification was specified using the new mechanism, so we can just handle it here - std::string notificationID; - std::string llsdRaw; - LLSD llsdBlock; - msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID); - msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_ExtraParams, llsdRaw); - if (llsdRaw.length()) - { - std::istringstream llsdData(llsdRaw); - if (!LLSDSerialize::deserialize(llsdBlock, llsdData, llsdRaw.length())) - { - llwarns << "attempt_standard_notification: Attempted to read notification parameter data into LLSD but failed:" << llsdRaw << llendl; - } - } - - if ( - (notificationID == "RegionEntryAccessBlocked") || - (notificationID == "LandClaimAccessBlocked") || - (notificationID == "LandBuyAccessBlocked") - ) - { - /*--------------------------------------------------------------------- - (Commented so a grep will find the notification strings, since - we construct them on the fly; if you add additional notifications, - please update the comment.) - - Could throw any of the following notifications: - - RegionEntryAccessBlocked - RegionEntryAccessBlocked_Notify - RegionEntryAccessBlocked_Change - RegionEntryAccessBlocked_KB - LandClaimAccessBlocked - LandClaimAccessBlocked_Notify - LandClaimAccessBlocked_Change - LandClaimAccessBlocked_KB - LandBuyAccessBlocked - LandBuyAccessBlocked_Notify - LandBuyAccessBlocked_Change - LandBuyAccessBlocked_KB - - -----------------------------------------------------------------------*/ - if (handle_special_notification(notificationID, llsdBlock)) - { - return true; - } - } - - LLNotificationsUtil::add(notificationID, llsdBlock); - return true; - } - return false; -} - - -void process_agent_alert_message(LLMessageSystem* msgsystem, void** user_data) -{ - // make sure the cursor is back to the usual default since the - // alert is probably due to some kind of error. - gViewerWindow->getWindow()->resetBusyCount(); - - if (!attempt_standard_notification(msgsystem)) - { - BOOL modal = FALSE; - msgsystem->getBOOL("AlertData", "Modal", modal); - std::string buffer; - msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, buffer); - process_alert_core(buffer, modal); - } -} - -// The only difference between this routine and the previous is the fact that -// for this routine, the modal parameter is always false. Sadly, for the message -// handled by this routine, there is no "Modal" parameter on the message, and -// there's no API to tell if a message has the given parameter or not. -// So we can't handle the messages with the same handler. -void process_alert_message(LLMessageSystem *msgsystem, void **user_data) -{ - // make sure the cursor is back to the usual default since the - // alert is probably due to some kind of error. - gViewerWindow->getWindow()->resetBusyCount(); - - if (!attempt_standard_notification(msgsystem)) - { - BOOL modal = FALSE; - std::string buffer; - msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, buffer); - process_alert_core(buffer, modal); - } -} - -void process_alert_core(const std::string& message, BOOL modal) -{ - // HACK -- handle callbacks for specific alerts. It also is localized in notifications.xml - if ( message == "You died and have been teleported to your home location") - { - LLViewerStats::getInstance()->incStat(LLViewerStats::ST_KILLED_COUNT); - } - else if( message == "Home position set." ) - { - // save the home location image to disk - std::string snap_filename = gDirUtilp->getLindenUserDir(); - snap_filename += gDirUtilp->getDirDelimiter(); - snap_filename += SCREEN_HOME_FILENAME; - gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw(), FALSE, FALSE); - } - - const std::string ALERT_PREFIX("ALERT: "); - const std::string NOTIFY_PREFIX("NOTIFY: "); - if (message.find(ALERT_PREFIX) == 0) - { - // Allow the server to spawn a named alert so that server alerts can be - // translated out of English. - std::string alert_name(message.substr(ALERT_PREFIX.length())); - LLNotificationsUtil::add(alert_name); - } - else if (message.find(NOTIFY_PREFIX) == 0) - { - // Allow the server to spawn a named notification so that server notifications can be - // translated out of English. - std::string notify_name(message.substr(NOTIFY_PREFIX.length())); - LLNotificationsUtil::add(notify_name); - } - else if (message[0] == '/') - { - // System message is important, show in upper-right box not tip - std::string text(message.substr(1)); - LLSD args; - if (text.substr(0,17) == "RESTART_X_MINUTES") - { - S32 mins = 0; - LLStringUtil::convertToS32(text.substr(18), mins); - args["MINUTES"] = llformat("%d",mins); - LLNotificationsUtil::add("RegionRestartMinutes", args); - } - else if (text.substr(0,17) == "RESTART_X_SECONDS") - { - S32 secs = 0; - LLStringUtil::convertToS32(text.substr(18), secs); - args["SECONDS"] = llformat("%d",secs); - LLNotificationsUtil::add("RegionRestartSeconds", args); - } - else - { - std::string new_msg =LLNotifications::instance().getGlobalString(text); - args["MESSAGE"] = new_msg; - LLNotificationsUtil::add("SystemMessage", args); - } - } - else if (modal) - { - LLSD args; - std::string new_msg =LLNotifications::instance().getGlobalString(message); - args["ERROR_MESSAGE"] = new_msg; - LLNotificationsUtil::add("ErrorMessage", args); - } - else - { - LLSD args; - std::string new_msg =LLNotifications::instance().getGlobalString(message); - args["MESSAGE"] = new_msg; - LLNotificationsUtil::add("SystemMessageTip", args); - } -} - -mean_collision_list_t gMeanCollisionList; -time_t gLastDisplayedTime = 0; - -void handle_show_mean_events(void *) -{ - if (gNoRender) - { - return; - } - LLFloaterReg::showInstance("bumps"); - //LLFloaterBump::showInstance(); -} - -void mean_name_callback(const LLUUID &id, const std::string& full_name, bool is_group) -{ - if (gNoRender) - { - return; - } - - static const U32 max_collision_list_size = 20; - if (gMeanCollisionList.size() > max_collision_list_size) - { - mean_collision_list_t::iterator iter = gMeanCollisionList.begin(); - for (U32 i=0; i<max_collision_list_size; i++) iter++; - for_each(iter, gMeanCollisionList.end(), DeletePointer()); - gMeanCollisionList.erase(iter, gMeanCollisionList.end()); - } - - for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin(); - iter != gMeanCollisionList.end(); ++iter) - { - LLMeanCollisionData *mcd = *iter; - if (mcd->mPerp == id) - { - mcd->mFullName = full_name; - } - } -} - -void process_mean_collision_alert_message(LLMessageSystem *msgsystem, void **user_data) -{ - if (gAgent.inPrelude()) - { - // In prelude, bumping is OK. This dialog is rather confusing to - // newbies, so we don't show it. Drop the packet on the floor. - return; - } - - // make sure the cursor is back to the usual default since the - // alert is probably due to some kind of error. - gViewerWindow->getWindow()->resetBusyCount(); - - LLUUID perp; - U32 time; - U8 u8type; - EMeanCollisionType type; - F32 mag; - - S32 i, num = msgsystem->getNumberOfBlocks(_PREHASH_MeanCollision); - - for (i = 0; i < num; i++) - { - msgsystem->getUUIDFast(_PREHASH_MeanCollision, _PREHASH_Perp, perp); - msgsystem->getU32Fast(_PREHASH_MeanCollision, _PREHASH_Time, time); - msgsystem->getF32Fast(_PREHASH_MeanCollision, _PREHASH_Mag, mag); - msgsystem->getU8Fast(_PREHASH_MeanCollision, _PREHASH_Type, u8type); - - type = (EMeanCollisionType)u8type; - - BOOL b_found = FALSE; - - for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin(); - iter != gMeanCollisionList.end(); ++iter) - { - LLMeanCollisionData *mcd = *iter; - if ((mcd->mPerp == perp) && (mcd->mType == type)) - { - mcd->mTime = time; - mcd->mMag = mag; - b_found = TRUE; - break; - } - } - - if (!b_found) - { - LLMeanCollisionData *mcd = new LLMeanCollisionData(gAgentID, perp, time, type, mag); - gMeanCollisionList.push_front(mcd); - gCacheName->get(perp, false, boost::bind(&mean_name_callback, _1, _2, _3)); - } - } -} - -void process_frozen_message(LLMessageSystem *msgsystem, void **user_data) -{ - // make sure the cursor is back to the usual default since the - // alert is probably due to some kind of error. - gViewerWindow->getWindow()->resetBusyCount(); - BOOL b_frozen; - - msgsystem->getBOOL("FrozenData", "Data", b_frozen); - - // TODO: make being frozen change view - if (b_frozen) - { - } - else - { - } -} - -// do some extra stuff once we get our economy data -void process_economy_data(LLMessageSystem *msg, void** /*user_data*/) -{ - LLGlobalEconomy::processEconomyData(msg, LLGlobalEconomy::Singleton::getInstance()); - - S32 upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); - - LL_INFOS_ONCE("Messaging") << "EconomyData message arrived; upload cost is L$" << upload_cost << LL_ENDL; - - gMenuHolder->getChild<LLUICtrl>("Upload Image")->setLabelArg("[COST]", llformat("%d", upload_cost)); - gMenuHolder->getChild<LLUICtrl>("Upload Sound")->setLabelArg("[COST]", llformat("%d", upload_cost)); - gMenuHolder->getChild<LLUICtrl>("Upload Animation")->setLabelArg("[COST]", llformat("%d", upload_cost)); - gMenuHolder->getChild<LLUICtrl>("Bulk Upload")->setLabelArg("[COST]", llformat("%d", upload_cost)); -} - -void notify_cautioned_script_question(const LLSD& notification, const LLSD& response, S32 orig_questions, BOOL granted) -{ - // only continue if at least some permissions were requested - if (orig_questions) - { - // check to see if the person we are asking - - // "'[OBJECTNAME]', an object owned by '[OWNERNAME]', - // located in [REGIONNAME] at [REGIONPOS], - // has been <granted|denied> permission to: [PERMISSIONS]." - - LLUIString notice(LLTrans::getString(granted ? "ScriptQuestionCautionChatGranted" : "ScriptQuestionCautionChatDenied")); - - // always include the object name and owner name - notice.setArg("[OBJECTNAME]", notification["payload"]["object_name"].asString()); - notice.setArg("[OWNERNAME]", notification["payload"]["owner_name"].asString()); - - // try to lookup viewerobject that corresponds to the object that - // requested permissions (here, taskid->requesting object id) - BOOL foundpos = FALSE; - LLViewerObject* viewobj = gObjectList.findObject(notification["payload"]["task_id"].asUUID()); - if (viewobj) - { - // found the viewerobject, get it's position in its region - LLVector3 objpos(viewobj->getPosition()); - - // try to lookup the name of the region the object is in - LLViewerRegion* viewregion = viewobj->getRegion(); - if (viewregion) - { - // got the region, so include the region and 3d coordinates of the object - notice.setArg("[REGIONNAME]", viewregion->getName()); - std::string formatpos = llformat("%.1f, %.1f,%.1f", objpos[VX], objpos[VY], objpos[VZ]); - notice.setArg("[REGIONPOS]", formatpos); - - foundpos = TRUE; - } - } - - if (!foundpos) - { - // unable to determine location of the object - notice.setArg("[REGIONNAME]", "(unknown region)"); - notice.setArg("[REGIONPOS]", "(unknown position)"); - } - - // check each permission that was requested, and list each - // permission that has been flagged as a caution permission - BOOL caution = FALSE; - S32 count = 0; - std::string perms; - for (S32 i = 0; i < SCRIPT_PERMISSION_EOF; i++) - { - if ((orig_questions & LSCRIPTRunTimePermissionBits[i]) && SCRIPT_QUESTION_IS_CAUTION[i]) - { - count++; - caution = TRUE; - - // add a comma before the permission description if it is not the first permission - // added to the list or the last permission to check - if ((count > 1) && (i < SCRIPT_PERMISSION_EOF)) - { - perms.append(", "); - } - - perms.append(LLTrans::getString(SCRIPT_QUESTIONS[i])); - } - } - - notice.setArg("[PERMISSIONS]", perms); - - // log a chat message as long as at least one requested permission - // is a caution permission - if (caution) - { - LLChat chat(notice.getString()); - // LLFloaterChat::addChat(chat, FALSE, FALSE); - } - } -} - -bool script_question_cb(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - LLMessageSystem *msg = gMessageSystem; - S32 orig = notification["payload"]["questions"].asInteger(); - S32 new_questions = orig; - - // check whether permissions were granted or denied - BOOL allowed = TRUE; - // the "yes/accept" button is the first button in the template, making it button 0 - // if any other button was clicked, the permissions were denied - if (option != 0) - { - new_questions = 0; - allowed = FALSE; - } - - LLUUID task_id = notification["payload"]["task_id"].asUUID(); - LLUUID item_id = notification["payload"]["item_id"].asUUID(); - - // reply with the permissions granted or denied - msg->newMessageFast(_PREHASH_ScriptAnswerYes); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_Data); - msg->addUUIDFast(_PREHASH_TaskID, task_id); - msg->addUUIDFast(_PREHASH_ItemID, item_id); - msg->addS32Fast(_PREHASH_Questions, new_questions); - msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); - - // only log a chat message if caution prompts are enabled - if (gSavedSettings.getBOOL("PermissionsCautionEnabled")) - { - // log a chat message, if appropriate - notify_cautioned_script_question(notification, response, orig, allowed); - } - - if ( response["Mute"] ) // mute - { - LLMuteList::getInstance()->add(LLMute(item_id, notification["payload"]["object_name"].asString(), LLMute::OBJECT)); - - // purge the message queue of any previously queued requests from the same source. DEV-4879 - class OfferMatcher : public LLNotificationsUI::LLScreenChannel::Matcher - { - public: - OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {} - bool matches(const LLNotificationPtr notification) const - { - if (notification->getName() == "ScriptQuestionCaution" - || notification->getName() == "ScriptQuestion") - { - return (notification->getPayload()["item_id"].asUUID() == blocked_id); - } - return false; - } - private: - const LLUUID& blocked_id; - }; - - LLNotificationsUI::LLChannelManager::getInstance()->killToastsFromChannel(LLUUID( - gSavedSettings.getString("NotificationChannelUUID")), OfferMatcher(item_id)); - } - - if (response["Details"]) - { - // respawn notification... - LLNotificationsUtil::add(notification["name"], notification["substitutions"], notification["payload"]); - - // ...with description on top - LLNotificationsUtil::add("DebitPermissionDetails"); - } - return false; -} -static LLNotificationFunctorRegistration script_question_cb_reg_1("ScriptQuestion", script_question_cb); -static LLNotificationFunctorRegistration script_question_cb_reg_2("ScriptQuestionCaution", script_question_cb); - -void process_script_question(LLMessageSystem *msg, void **user_data) -{ - // *TODO: Translate owner name -> [FIRST] [LAST] - - LLHost sender = msg->getSender(); - - LLUUID taskid; - LLUUID itemid; - S32 questions; - std::string object_name; - std::string owner_name; - - // taskid -> object key of object requesting permissions - msg->getUUIDFast(_PREHASH_Data, _PREHASH_TaskID, taskid ); - // itemid -> script asset key of script requesting permissions - msg->getUUIDFast(_PREHASH_Data, _PREHASH_ItemID, itemid ); - msg->getStringFast(_PREHASH_Data, _PREHASH_ObjectName, object_name); - msg->getStringFast(_PREHASH_Data, _PREHASH_ObjectOwner, owner_name); - msg->getS32Fast(_PREHASH_Data, _PREHASH_Questions, questions ); - - // Special case. If the objects are owned by this agent, throttle per-object instead - // of per-owner. It's common for residents to reset a ton of scripts that re-request - // permissions, as with tier boxes. UUIDs can't be valid agent names and vice-versa, - // so we'll reuse the same namespace for both throttle types. - std::string throttle_name = owner_name; - std::string self_name; - LLAgentUI::buildFullname( self_name ); - if( owner_name == self_name ) - { - throttle_name = taskid.getString(); - } - - // don't display permission requests if this object is muted - if (LLMuteList::getInstance()->isMuted(taskid)) return; - - // throttle excessive requests from any specific user's scripts - typedef LLKeyThrottle<std::string> LLStringThrottle; - static LLStringThrottle question_throttle( LLREQUEST_PERMISSION_THROTTLE_LIMIT, LLREQUEST_PERMISSION_THROTTLE_INTERVAL ); - - switch (question_throttle.noteAction(throttle_name)) - { - case LLStringThrottle::THROTTLE_NEWLY_BLOCKED: - LL_INFOS("Messaging") << "process_script_question throttled" - << " owner_name:" << owner_name - << LL_ENDL; - // Fall through - - case LLStringThrottle::THROTTLE_BLOCKED: - // Escape altogether until we recover - return; - - case LLStringThrottle::THROTTLE_OK: - break; - } - - std::string script_question; - if (questions) - { - BOOL caution = FALSE; - S32 count = 0; - LLSD args; - args["OBJECTNAME"] = object_name; - args["NAME"] = LLCacheName::cleanFullName(owner_name); - - // check the received permission flags against each permission - for (S32 i = 0; i < SCRIPT_PERMISSION_EOF; i++) - { - if (questions & LSCRIPTRunTimePermissionBits[i]) - { - count++; - script_question += " " + LLTrans::getString(SCRIPT_QUESTIONS[i]) + "\n"; - - // check whether permission question should cause special caution dialog - caution |= (SCRIPT_QUESTION_IS_CAUTION[i]); - } - } - args["QUESTIONS"] = script_question; - - LLSD payload; - payload["task_id"] = taskid; - payload["item_id"] = itemid; - payload["sender"] = sender.getIPandPort(); - payload["questions"] = questions; - payload["object_name"] = object_name; - payload["owner_name"] = owner_name; - - // check whether cautions are even enabled or not - if (gSavedSettings.getBOOL("PermissionsCautionEnabled")) - { - // display the caution permissions prompt - LLNotificationsUtil::add(caution ? "ScriptQuestionCaution" : "ScriptQuestion", args, payload); - } - else - { - // fall back to default behavior if cautions are entirely disabled - LLNotificationsUtil::add("ScriptQuestion", args, payload); - } - - } -} - - -void process_derez_container(LLMessageSystem *msg, void**) -{ - LL_WARNS("Messaging") << "call to deprecated process_derez_container" << LL_ENDL; -} - -void container_inventory_arrived(LLViewerObject* object, - LLInventoryObject::object_list_t* inventory, - S32 serial_num, - void* data) -{ - LL_DEBUGS("Messaging") << "container_inventory_arrived()" << LL_ENDL; - if( gAgentCamera.cameraMouselook() ) - { - gAgentCamera.changeCameraToDefault(); - } - - LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(); - - if (inventory->size() > 2) - { - // create a new inventory category to put this in - LLUUID cat_id; - cat_id = gInventory.createNewCategory(gInventory.getRootFolderID(), - LLFolderType::FT_NONE, - LLTrans::getString("AcquiredItems")); - - LLInventoryObject::object_list_t::const_iterator it = inventory->begin(); - LLInventoryObject::object_list_t::const_iterator end = inventory->end(); - for ( ; it != end; ++it) - { - if ((*it)->getType() != LLAssetType::AT_CATEGORY) - { - LLInventoryObject* obj = (LLInventoryObject*)(*it); - LLInventoryItem* item = (LLInventoryItem*)(obj); - LLUUID item_id; - item_id.generate(); - time_t creation_date_utc = time_corrected(); - LLPointer<LLViewerInventoryItem> new_item - = new LLViewerInventoryItem(item_id, - cat_id, - item->getPermissions(), - item->getAssetUUID(), - item->getType(), - item->getInventoryType(), - item->getName(), - item->getDescription(), - LLSaleInfo::DEFAULT, - item->getFlags(), - creation_date_utc); - new_item->updateServer(TRUE); - gInventory.updateItem(new_item); - } - } - gInventory.notifyObservers(); - if(active_panel) - { - active_panel->setSelection(cat_id, TAKE_FOCUS_NO); - } - } - else if (inventory->size() == 2) - { - // we're going to get one fake root category as well as the - // one actual object - LLInventoryObject::object_list_t::iterator it = inventory->begin(); - - if ((*it)->getType() == LLAssetType::AT_CATEGORY) - { - ++it; - } - - LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it)); - const LLUUID category = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(item->getType())); - - LLUUID item_id; - item_id.generate(); - time_t creation_date_utc = time_corrected(); - LLPointer<LLViewerInventoryItem> new_item - = new LLViewerInventoryItem(item_id, category, - item->getPermissions(), - item->getAssetUUID(), - item->getType(), - item->getInventoryType(), - item->getName(), - item->getDescription(), - LLSaleInfo::DEFAULT, - item->getFlags(), - creation_date_utc); - new_item->updateServer(TRUE); - gInventory.updateItem(new_item); - gInventory.notifyObservers(); - if(active_panel) - { - active_panel->setSelection(item_id, TAKE_FOCUS_NO); - } - } - - // we've got the inventory, now delete this object if this was a take - BOOL delete_object = (BOOL)(intptr_t)data; - LLViewerRegion *region = gAgent.getRegion(); - if (delete_object && region) - { - gMessageSystem->newMessageFast(_PREHASH_ObjectDelete); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - const U8 NO_FORCE = 0; - gMessageSystem->addU8Fast(_PREHASH_Force, NO_FORCE); - gMessageSystem->nextBlockFast(_PREHASH_ObjectData); - gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID()); - gMessageSystem->sendReliable(region->getHost()); - } -} - -// method to format the time. -std::string formatted_time(const time_t& the_time) -{ - std::string dateStr = "["+LLTrans::getString("LTimeWeek")+"] [" - +LLTrans::getString("LTimeMonth")+"] [" - +LLTrans::getString("LTimeDay")+"] [" - +LLTrans::getString("LTimeHour")+"]:[" - +LLTrans::getString("LTimeMin")+"]:[" - +LLTrans::getString("LTimeSec")+"] [" - +LLTrans::getString("LTimeYear")+"]"; - - LLSD substitution; - substitution["datetime"] = (S32) the_time; - LLStringUtil::format (dateStr, substitution); - return dateStr; -} - - -void process_teleport_failed(LLMessageSystem *msg, void**) -{ - std::string reason; - std::string big_reason; - LLSD args; - - // if we have additional alert data - if (msg->has(_PREHASH_AlertInfo) && msg->getSizeFast(_PREHASH_AlertInfo, _PREHASH_Message) > 0) - { - // Get the message ID - msg->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, reason); - big_reason = LLAgent::sTeleportErrorMessages[reason]; - if ( big_reason.size() > 0 ) - { // Substitute verbose reason from the local map - args["REASON"] = big_reason; - } - else - { // Nothing found in the map - use what the server returned in the original message block - msg->getStringFast(_PREHASH_Info, _PREHASH_Reason, reason); - args["REASON"] = reason; - } - - LLSD llsd_block; - std::string llsd_raw; - msg->getStringFast(_PREHASH_AlertInfo, _PREHASH_ExtraParams, llsd_raw); - if (llsd_raw.length()) - { - std::istringstream llsd_data(llsd_raw); - if (!LLSDSerialize::deserialize(llsd_block, llsd_data, llsd_raw.length())) - { - llwarns << "process_teleport_failed: Attempted to read alert parameter data into LLSD but failed:" << llsd_raw << llendl; - } - else - { - // change notification name in this special case - if (handle_special_notification("RegionEntryAccessBlocked", llsd_block)) - { - if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) - { - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); - } - return; - } - } - } - - } - else - { - msg->getStringFast(_PREHASH_Info, _PREHASH_Reason, reason); - - big_reason = LLAgent::sTeleportErrorMessages[reason]; - if ( big_reason.size() > 0 ) - { // Substitute verbose reason from the local map - args["REASON"] = big_reason; - } - else - { // Nothing found in the map - use what the server returned - args["REASON"] = reason; - } - } - - LLNotificationsUtil::add("CouldNotTeleportReason", args); - - // Let the interested parties know that teleport failed. - LLViewerParcelMgr::getInstance()->onTeleportFailed(); - - if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) - { - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); - } -} - -void process_teleport_local(LLMessageSystem *msg,void**) -{ - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_Info, _PREHASH_AgentID, agent_id); - if (agent_id != gAgent.getID()) - { - LL_WARNS("Messaging") << "Got teleport notification for wrong agent!" << LL_ENDL; - return; - } - - U32 location_id; - LLVector3 pos, look_at; - U32 teleport_flags; - msg->getU32Fast(_PREHASH_Info, _PREHASH_LocationID, location_id); - msg->getVector3Fast(_PREHASH_Info, _PREHASH_Position, pos); - msg->getVector3Fast(_PREHASH_Info, _PREHASH_LookAt, look_at); - msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags); - - if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) - { - if( gAgent.getTeleportState() == LLAgent::TELEPORT_LOCAL ) - { - // To prevent TeleportStart messages re-activating the progress screen right - // after tp, keep the teleport state and let progress screen clear it after a short delay - // (progress screen is active but not visible) *TODO: remove when SVC-5290 is fixed - gTeleportDisplayTimer.reset(); - gTeleportDisplay = TRUE; - } - else - { - gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); - } - } - - // Sim tells us whether the new position is off the ground - if (teleport_flags & TELEPORT_FLAGS_IS_FLYING) - { - gAgent.setFlying(TRUE); - } - else - { - gAgent.setFlying(FALSE); - } - - gAgent.setPositionAgent(pos); - gAgentCamera.slamLookAt(look_at); - - if ( !(gAgent.getTeleportKeepsLookAt() && LLViewerJoystick::getInstance()->getOverrideCamera()) ) - { - gAgentCamera.resetView(TRUE, TRUE); - } - - // send camera update to new region - gAgentCamera.updateCamera(); - - send_agent_update(TRUE, TRUE); - - // Let the interested parties know we've teleported. - // Vadim *HACK: Agent position seems to get reset (to render position?) - // on each frame, so we have to pass the new position manually. - LLViewerParcelMgr::getInstance()->onTeleportFinished(true, gAgent.getPosGlobalFromAgent(pos)); -} - -void send_simple_im(const LLUUID& to_id, - const std::string& message, - EInstantMessage dialog, - const LLUUID& id) -{ - std::string my_name; - LLAgentUI::buildFullname(my_name); - send_improved_im(to_id, - my_name, - message, - IM_ONLINE, - dialog, - id, - NO_TIMESTAMP, - (U8*)EMPTY_BINARY_BUCKET, - EMPTY_BINARY_BUCKET_SIZE); -} - -void send_group_notice(const LLUUID& group_id, - const std::string& subject, - const std::string& message, - const LLInventoryItem* item) -{ - // Put this notice into an instant message form. - // This will mean converting the item to a binary bucket, - // and the subject/message into a single field. - std::string my_name; - LLAgentUI::buildFullname(my_name); - - // Combine subject + message into a single string. - std::ostringstream subject_and_message; - // TODO: turn all existing |'s into ||'s in subject and message. - subject_and_message << subject << "|" << message; - - // Create an empty binary bucket. - U8 bin_bucket[MAX_INVENTORY_BUFFER_SIZE]; - U8* bucket_to_send = bin_bucket; - bin_bucket[0] = '\0'; - S32 bin_bucket_size = EMPTY_BINARY_BUCKET_SIZE; - // If there is an item being sent, pack it into the binary bucket. - if (item) - { - LLSD item_def; - item_def["item_id"] = item->getUUID(); - item_def["owner_id"] = item->getPermissions().getOwner(); - std::ostringstream ostr; - LLSDSerialize::serialize(item_def, ostr, LLSDSerialize::LLSD_XML); - bin_bucket_size = ostr.str().copy( - (char*)bin_bucket, ostr.str().size()); - bin_bucket[bin_bucket_size] = '\0'; - } - else - { - bucket_to_send = (U8*) EMPTY_BINARY_BUCKET; - } - - - send_improved_im( - group_id, - my_name, - subject_and_message.str(), - IM_ONLINE, - IM_GROUP_NOTICE, - LLUUID::null, - NO_TIMESTAMP, - bucket_to_send, - bin_bucket_size); -} - -bool handle_lure_callback(const LLSD& notification, const LLSD& response) -{ - std::string text = response["message"].asString(); - LLSLURL slurl; - LLAgentUI::buildSLURL(slurl); - text.append("\r\n").append(slurl.getSLURLString()); - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - if(0 == option) - { - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_StartLure); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_Info); - msg->addU8Fast(_PREHASH_LureType, (U8)0); // sim will fill this in. - msg->addStringFast(_PREHASH_Message, text); - for(LLSD::array_const_iterator it = notification["payload"]["ids"].beginArray(); - it != notification["payload"]["ids"].endArray(); - ++it) - { - LLUUID target_id = it->asUUID(); - - msg->nextBlockFast(_PREHASH_TargetData); - msg->addUUIDFast(_PREHASH_TargetID, target_id); - - // Record the offer. - { - std::string target_name; - gCacheName->getFullName(target_id, target_name); // for im log filenames - LLSD args; - args["TO_NAME"] = LLSLURL("agent", target_id, "displayname").getSLURLString();; - - LLSD payload; - - //*TODO please rewrite all keys to the same case, lower or upper - payload["from_id"] = target_id; - payload["SUPPRESS_TOAST"] = true; - LLNotificationsUtil::add("TeleportOfferSent", args, payload); - - // Add the recepient to the recent people list. - LLRecentPeople::instance().add(target_id); - } - } - gAgent.sendReliableMessage(); - } - - return false; -} - -void handle_lure(const LLUUID& invitee) -{ - LLDynamicArray<LLUUID> ids; - ids.push_back(invitee); - handle_lure(ids); -} - -// Prompt for a message to the invited user. -void handle_lure(const uuid_vec_t& ids) -{ - if (ids.empty()) return; - - if (!gAgent.getRegion()) return; - - LLSD edit_args; - edit_args["REGION"] = gAgent.getRegion()->getName(); - - LLSD payload; - for (LLDynamicArray<LLUUID>::const_iterator it = ids.begin(); - it != ids.end(); - ++it) - { - payload["ids"].append(*it); - } - if (gAgent.isGodlike()) - { - LLNotificationsUtil::add("OfferTeleportFromGod", edit_args, payload, handle_lure_callback); - } - else - { - LLNotificationsUtil::add("OfferTeleport", edit_args, payload, handle_lure_callback); - } -} - - -void send_improved_im(const LLUUID& to_id, - const std::string& name, - const std::string& message, - U8 offline, - EInstantMessage dialog, - const LLUUID& id, - U32 timestamp, - const U8* binary_bucket, - S32 binary_bucket_size) -{ - pack_instant_message( - gMessageSystem, - gAgent.getID(), - FALSE, - gAgent.getSessionID(), - to_id, - name, - message, - offline, - dialog, - id, - 0, - LLUUID::null, - gAgent.getPositionAgent(), - timestamp, - binary_bucket, - binary_bucket_size); - gAgent.sendReliableMessage(); -} - - -void send_places_query(const LLUUID& query_id, - const LLUUID& trans_id, - const std::string& query_text, - U32 query_flags, - S32 category, - const std::string& sim_name) -{ - LLMessageSystem* msg = gMessageSystem; - - msg->newMessage("PlacesQuery"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->addUUID("QueryID", query_id); - msg->nextBlock("TransactionData"); - msg->addUUID("TransactionID", trans_id); - msg->nextBlock("QueryData"); - msg->addString("QueryText", query_text); - msg->addU32("QueryFlags", query_flags); - msg->addS8("Category", (S8)category); - msg->addString("SimName", sim_name); - gAgent.sendReliableMessage(); -} - - -void process_user_info_reply(LLMessageSystem* msg, void**) -{ - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - if(agent_id != gAgent.getID()) - { - LL_WARNS("Messaging") << "process_user_info_reply - " - << "wrong agent id." << LL_ENDL; - } - - BOOL im_via_email; - msg->getBOOLFast(_PREHASH_UserData, _PREHASH_IMViaEMail, im_via_email); - std::string email; - msg->getStringFast(_PREHASH_UserData, _PREHASH_EMail, email); - std::string dir_visibility; - msg->getString( "UserData", "DirectoryVisibility", dir_visibility); - - LLFloaterPreference::updateUserInfo(dir_visibility, im_via_email, email); - LLFloaterPostcard::updateUserInfo(email); -} - - -//--------------------------------------------------------------------------- -// Script Dialog -//--------------------------------------------------------------------------- - -const S32 SCRIPT_DIALOG_MAX_BUTTONS = 12; -const S32 SCRIPT_DIALOG_BUTTON_STR_SIZE = 24; -const S32 SCRIPT_DIALOG_MAX_MESSAGE_SIZE = 512; -const char* SCRIPT_DIALOG_HEADER = "Script Dialog:\n"; - -bool callback_script_dialog(const LLSD& notification, const LLSD& response) -{ - LLNotificationForm form(notification["form"]); - - std::string rtn_text; - S32 button_idx; - button_idx = LLNotification::getSelectedOption(notification, response); - if (response[TEXTBOX_MAGIC_TOKEN].isDefined()) - { - if (response[TEXTBOX_MAGIC_TOKEN].isString()) - rtn_text = response[TEXTBOX_MAGIC_TOKEN].asString(); - else - rtn_text.clear(); // bool marks empty string - } - else - { - rtn_text = LLNotification::getSelectedOptionName(response); - } - - // Didn't click "Ignore" - if (button_idx != -1) - { - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("ScriptDialogReply"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("Data"); - msg->addUUID("ObjectID", notification["payload"]["object_id"].asUUID()); - msg->addS32("ChatChannel", notification["payload"]["chat_channel"].asInteger()); - msg->addS32("ButtonIndex", button_idx); - msg->addString("ButtonLabel", rtn_text); - msg->sendReliable(LLHost(notification["payload"]["sender"].asString())); - } - - return false; -} -static LLNotificationFunctorRegistration callback_script_dialog_reg_1("ScriptDialog", callback_script_dialog); -static LLNotificationFunctorRegistration callback_script_dialog_reg_2("ScriptDialogGroup", callback_script_dialog); - -void process_script_dialog(LLMessageSystem* msg, void**) -{ - S32 i; - LLSD payload; - - LLUUID object_id; - msg->getUUID("Data", "ObjectID", object_id); - - if (LLMuteList::getInstance()->isMuted(object_id)) - { - return; - } - - std::string message; - std::string first_name; - std::string last_name; - std::string title; - - S32 chat_channel; - msg->getString("Data", "FirstName", first_name); - msg->getString("Data", "LastName", last_name); - msg->getString("Data", "ObjectName", title); - msg->getString("Data", "Message", message); - msg->getS32("Data", "ChatChannel", chat_channel); - - // unused for now - LLUUID image_id; - msg->getUUID("Data", "ImageID", image_id); - - payload["sender"] = msg->getSender().getIPandPort(); - payload["object_id"] = object_id; - payload["chat_channel"] = chat_channel; - - // build up custom form - S32 button_count = msg->getNumberOfBlocks("Buttons"); - if (button_count > SCRIPT_DIALOG_MAX_BUTTONS) - { - llwarns << "Too many script dialog buttons - omitting some" << llendl; - button_count = SCRIPT_DIALOG_MAX_BUTTONS; - } - - LLNotificationForm form; - for (i = 0; i < button_count; i++) - { - std::string tdesc; - msg->getString("Buttons", "ButtonLabel", tdesc, i); - form.addElement("button", std::string(tdesc)); - } - - LLSD args; - args["TITLE"] = title; - args["MESSAGE"] = message; - LLNotificationPtr notification; - if (!first_name.empty()) - { - args["NAME"] = LLCacheName::buildFullName(first_name, last_name); - notification = LLNotifications::instance().add( - LLNotification::Params("ScriptDialog").substitutions(args).payload(payload).form_elements(form.asLLSD())); - } - else - { - args["GROUPNAME"] = last_name; - notification = LLNotifications::instance().add( - LLNotification::Params("ScriptDialogGroup").substitutions(args).payload(payload).form_elements(form.asLLSD())); - } -} - -//--------------------------------------------------------------------------- - - -std::vector<LLSD> gLoadUrlList; - -bool callback_load_url(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - if (0 == option) - { - LLWeb::loadURL(notification["payload"]["url"].asString()); - } - - return false; -} -static LLNotificationFunctorRegistration callback_load_url_reg("LoadWebPage", callback_load_url); - - -// We've got the name of the person who owns the object hurling the url. -// Display confirmation dialog. -void callback_load_url_name(const LLUUID& id, const std::string& full_name, bool is_group) -{ - std::vector<LLSD>::iterator it; - for (it = gLoadUrlList.begin(); it != gLoadUrlList.end(); ) - { - LLSD load_url_info = *it; - if (load_url_info["owner_id"].asUUID() == id) - { - it = gLoadUrlList.erase(it); - - std::string owner_name; - if (is_group) - { - owner_name = full_name + LLTrans::getString("Group"); - } - else - { - owner_name = full_name; - } - - // For legacy name-only mutes. - if (LLMuteList::getInstance()->isMuted(LLUUID::null, owner_name)) - { - continue; - } - LLSD args; - args["URL"] = load_url_info["url"].asString(); - args["MESSAGE"] = load_url_info["message"].asString();; - args["OBJECTNAME"] = load_url_info["object_name"].asString(); - args["NAME"] = owner_name; - - LLNotificationsUtil::add("LoadWebPage", args, load_url_info); - } - else - { - ++it; - } - } -} - -void process_load_url(LLMessageSystem* msg, void**) -{ - LLUUID object_id; - LLUUID owner_id; - BOOL owner_is_group; - char object_name[256]; /* Flawfinder: ignore */ - char message[256]; /* Flawfinder: ignore */ - char url[256]; /* Flawfinder: ignore */ - - msg->getString("Data", "ObjectName", 256, object_name); - msg->getUUID( "Data", "ObjectID", object_id); - msg->getUUID( "Data", "OwnerID", owner_id); - msg->getBOOL( "Data", "OwnerIsGroup", owner_is_group); - msg->getString("Data", "Message", 256, message); - msg->getString("Data", "URL", 256, url); - - LLSD payload; - payload["object_id"] = object_id; - payload["owner_id"] = owner_id; - payload["owner_is_group"] = owner_is_group; - payload["object_name"] = object_name; - payload["message"] = message; - payload["url"] = url; - - // URL is safety checked in load_url above - - // Check if object or owner is muted - if (LLMuteList::getInstance()->isMuted(object_id, object_name) || - LLMuteList::getInstance()->isMuted(owner_id)) - { - LL_INFOS("Messaging")<<"Ignoring load_url from muted object/owner."<<LL_ENDL; - return; - } - - // Add to list of pending name lookups - gLoadUrlList.push_back(payload); - - gCacheName->get(owner_id, owner_is_group, - boost::bind(&callback_load_url_name, _1, _2, _3)); -} - - -void callback_download_complete(void** data, S32 result, LLExtStat ext_status) -{ - std::string* filepath = (std::string*)data; - LLSD args; - args["DOWNLOAD_PATH"] = *filepath; - LLNotificationsUtil::add("FinishedRawDownload", args); - delete filepath; -} - - -void process_initiate_download(LLMessageSystem* msg, void**) -{ - LLUUID agent_id; - msg->getUUID("AgentData", "AgentID", agent_id); - if (agent_id != gAgent.getID()) - { - LL_WARNS("Messaging") << "Initiate download for wrong agent" << LL_ENDL; - return; - } - - std::string sim_filename; - std::string viewer_filename; - msg->getString("FileData", "SimFilename", sim_filename); - msg->getString("FileData", "ViewerFilename", viewer_filename); - - if (!gXferManager->validateFileForRequest(viewer_filename)) - { - llwarns << "SECURITY: Unauthorized download to local file " << viewer_filename << llendl; - return; - } - gXferManager->requestFile(viewer_filename, - sim_filename, - LL_PATH_NONE, - msg->getSender(), - FALSE, // don't delete remote - callback_download_complete, - (void**)new std::string(viewer_filename)); -} - - -void process_script_teleport_request(LLMessageSystem* msg, void**) -{ - if (!gSavedSettings.getBOOL("ScriptsCanShowUI")) return; - - std::string object_name; - std::string sim_name; - LLVector3 pos; - LLVector3 look_at; - - msg->getString("Data", "ObjectName", object_name); - msg->getString("Data", "SimName", sim_name); - msg->getVector3("Data", "SimPosition", pos); - msg->getVector3("Data", "LookAt", look_at); - - LLFloaterWorldMap* instance = LLFloaterWorldMap::getInstance(); - if(instance) - { - instance->trackURL( - sim_name, (S32)pos.mV[VX], (S32)pos.mV[VY], (S32)pos.mV[VZ]); - LLFloaterReg::showInstance("world_map", "center"); - } - - // remove above two lines and replace with below line - // to re-enable parcel browser for llMapDestination() - // LLURLDispatcher::dispatch(LLSLURL::buildSLURL(sim_name, (S32)pos.mV[VX], (S32)pos.mV[VY], (S32)pos.mV[VZ]), FALSE); - -} - -void process_covenant_reply(LLMessageSystem* msg, void**) -{ - LLUUID covenant_id, estate_owner_id; - std::string estate_name; - U32 covenant_timestamp; - msg->getUUID("Data", "CovenantID", covenant_id); - msg->getU32("Data", "CovenantTimestamp", covenant_timestamp); - msg->getString("Data", "EstateName", estate_name); - msg->getUUID("Data", "EstateOwnerID", estate_owner_id); - - LLPanelEstateCovenant::updateEstateName(estate_name); - LLPanelLandCovenant::updateEstateName(estate_name); - LLFloaterBuyLand::updateEstateName(estate_name); - - std::string owner_name = - LLSLURL("agent", estate_owner_id, "inspect").getSLURLString(); - LLPanelEstateCovenant::updateEstateOwnerName(owner_name); - LLPanelLandCovenant::updateEstateOwnerName(owner_name); - LLFloaterBuyLand::updateEstateOwnerName(owner_name); - - LLPanelPlaceProfile* panel = LLSideTray::getInstance()->getPanel<LLPanelPlaceProfile>("panel_place_profile"); - if (panel) - { - panel->updateEstateName(estate_name); - panel->updateEstateOwnerName(owner_name); - } - - // standard message, not from system - std::string last_modified; - if (covenant_timestamp == 0) - { - last_modified = LLTrans::getString("covenant_last_modified")+LLTrans::getString("never_text"); - } - else - { - last_modified = LLTrans::getString("covenant_last_modified")+"[" - +LLTrans::getString("LTimeWeek")+"] [" - +LLTrans::getString("LTimeMonth")+"] [" - +LLTrans::getString("LTimeDay")+"] [" - +LLTrans::getString("LTimeHour")+"]:[" - +LLTrans::getString("LTimeMin")+"]:[" - +LLTrans::getString("LTimeSec")+"] [" - +LLTrans::getString("LTimeYear")+"]"; - LLSD substitution; - substitution["datetime"] = (S32) covenant_timestamp; - LLStringUtil::format (last_modified, substitution); - } - - LLPanelEstateCovenant::updateLastModified(last_modified); - LLPanelLandCovenant::updateLastModified(last_modified); - LLFloaterBuyLand::updateLastModified(last_modified); - - // load the actual covenant asset data - const BOOL high_priority = TRUE; - if (covenant_id.notNull()) - { - gAssetStorage->getEstateAsset(gAgent.getRegionHost(), - gAgent.getID(), - gAgent.getSessionID(), - covenant_id, - LLAssetType::AT_NOTECARD, - ET_Covenant, - onCovenantLoadComplete, - NULL, - high_priority); - } - else - { - std::string covenant_text; - if (estate_owner_id.isNull()) - { - // mainland - covenant_text = LLTrans::getString("RegionNoCovenant"); - } - else - { - covenant_text = LLTrans::getString("RegionNoCovenantOtherOwner"); - } - LLPanelEstateCovenant::updateCovenantText(covenant_text, covenant_id); - LLPanelLandCovenant::updateCovenantText(covenant_text); - LLFloaterBuyLand::updateCovenantText(covenant_text, covenant_id); - if (panel) - { - panel->updateCovenantText(covenant_text); - } - } -} - -void onCovenantLoadComplete(LLVFS *vfs, - const LLUUID& asset_uuid, - LLAssetType::EType type, - void* user_data, S32 status, LLExtStat ext_status) -{ - LL_DEBUGS("Messaging") << "onCovenantLoadComplete()" << LL_ENDL; - std::string covenant_text; - if(0 == status) - { - LLVFile file(vfs, asset_uuid, type, LLVFile::READ); - - S32 file_length = file.getSize(); - - std::vector<char> buffer(file_length+1); - file.read((U8*)&buffer[0], file_length); - // put a EOS at the end - buffer[file_length] = '\0'; - - if( (file_length > 19) && !strncmp( &buffer[0], "Linden text version", 19 ) ) - { - LLViewerTextEditor::Params params; - params.name("temp"); - params.max_text_length(file_length+1); - LLViewerTextEditor * editor = LLUICtrlFactory::create<LLViewerTextEditor> (params); - if( !editor->importBuffer( &buffer[0], file_length+1 ) ) - { - LL_WARNS("Messaging") << "Problem importing estate covenant." << LL_ENDL; - covenant_text = "Problem importing estate covenant."; - } - else - { - // Version 0 (just text, doesn't include version number) - covenant_text = editor->getText(); - } - delete editor; - } - else - { - LL_WARNS("Messaging") << "Problem importing estate covenant: Covenant file format error." << LL_ENDL; - covenant_text = "Problem importing estate covenant: Covenant file format error."; - } - } - else - { - LLViewerStats::getInstance()->incStat( LLViewerStats::ST_DOWNLOAD_FAILED ); - - if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status || - LL_ERR_FILE_EMPTY == status) - { - covenant_text = "Estate covenant notecard is missing from database."; - } - else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status) - { - covenant_text = "Insufficient permissions to view estate covenant."; - } - else - { - covenant_text = "Unable to load estate covenant at this time."; - } - - LL_WARNS("Messaging") << "Problem loading notecard: " << status << LL_ENDL; - } - LLPanelEstateCovenant::updateCovenantText(covenant_text, asset_uuid); - LLPanelLandCovenant::updateCovenantText(covenant_text); - LLFloaterBuyLand::updateCovenantText(covenant_text, asset_uuid); - - LLPanelPlaceProfile* panel = LLSideTray::getInstance()->getPanel<LLPanelPlaceProfile>("panel_place_profile"); - if (panel) - { - panel->updateCovenantText(covenant_text); - } -} - - -void process_feature_disabled_message(LLMessageSystem* msg, void**) -{ - // Handle Blacklisted feature simulator response... - LLUUID agentID; - LLUUID transactionID; - std::string messageText; - msg->getStringFast(_PREHASH_FailureInfo,_PREHASH_ErrorMessage, messageText,0); - msg->getUUIDFast(_PREHASH_FailureInfo,_PREHASH_AgentID,agentID); - msg->getUUIDFast(_PREHASH_FailureInfo,_PREHASH_TransactionID,transactionID); - - LL_WARNS("Messaging") << "Blacklisted Feature Response:" << messageText << LL_ENDL; -} - -// ------------------------------------------------------------ -// Message system exception callbacks -// ------------------------------------------------------------ - -void invalid_message_callback(LLMessageSystem* msg, - void*, - EMessageException exception) -{ - LLAppViewer::instance()->badNetworkHandler(); -} - -// Please do not add more message handlers here. This file is huge. -// Put them in a file related to the functionality you are implementing. - -void LLOfferInfo::forceResponse(InventoryOfferResponse response) -{ - LLNotification::Params params("UserGiveItem"); - params.functor.function(boost::bind(&LLOfferInfo::inventory_offer_callback, this, _1, _2)); - LLNotifications::instance().forceResponse(params, response); -} - +/**
+ * @file llviewermessage.cpp
+ * @brief Dumping ground for viewer-side message system callbacks.
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llviewermessage.h"
+#include "boost/lexical_cast.hpp"
+
+// Linden libraries
+#include "llanimationstates.h"
+#include "llaudioengine.h"
+#include "llavataractions.h"
+#include "llavatarnamecache.h" // IDEVO HACK
+#include "lscript_byteformat.h"
+#include "lleconomy.h"
+#include "lleventtimer.h"
+#include "llfloaterreg.h"
+#include "llfollowcamparams.h"
+#include "llinventorydefines.h"
+#include "lllslconstants.h"
+#include "llregionhandle.h"
+#include "llsdserialize.h"
+#include "llteleportflags.h"
+#include "lltransactionflags.h"
+#include "llvfile.h"
+#include "llvfs.h"
+#include "llxfermanager.h"
+#include "mean_collision_data.h"
+
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llcallingcard.h"
+#include "llbuycurrencyhtml.h"
+#include "llfirstuse.h"
+#include "llfloaterbuyland.h"
+#include "llfloaterland.h"
+#include "llfloaterregioninfo.h"
+#include "llfloaterlandholdings.h"
+#include "llfloaterpostcard.h"
+#include "llfloaterpreference.h"
+#include "llhudeffecttrail.h"
+#include "llhudmanager.h"
+#include "llinventoryfunctions.h"
+#include "llinventoryobserver.h"
+#include "llinventorypanel.h"
+#include "llnearbychat.h"
+#include "llnotifications.h"
+#include "llnotificationsutil.h"
+#include "llpanelgrouplandmoney.h"
+#include "llrecentpeople.h"
+#include "llscriptfloater.h"
+#include "llselectmgr.h"
+#include "llsidetray.h"
+#include "llstartup.h"
+#include "llsky.h"
+#include "llslurl.h"
+#include "llstatenums.h"
+#include "llstatusbar.h"
+#include "llimview.h"
+#include "llspeakers.h"
+#include "lltrans.h"
+#include "lltranslate.h"
+#include "llviewerfoldertype.h"
+#include "llvoavatar.h" // IDEVO HACK
+#include "lluri.h"
+#include "llviewergenericmessage.h"
+#include "llviewermenu.h"
+#include "llviewerjoystick.h"
+#include "llviewerobjectlist.h"
+#include "llviewerparcelmgr.h"
+#include "llviewerstats.h"
+#include "llviewertexteditor.h"
+#include "llviewerthrottle.h"
+#include "llviewerwindow.h"
+#include "llvlmanager.h"
+#include "llvoavatarself.h"
+#include "llvotextbubble.h"
+#include "llworld.h"
+#include "pipeline.h"
+#include "llfloaterworldmap.h"
+#include "llviewerdisplay.h"
+#include "llkeythrottle.h"
+#include "llgroupactions.h"
+#include "llagentui.h"
+#include "llpanelblockedlist.h"
+#include "llpanelplaceprofile.h"
+
+#include <boost/algorithm/string/split.hpp> //
+#include <boost/regex.hpp>
+
+#include "llnotificationmanager.h" //
+
+#if LL_MSVC
+// disable boost::lexical_cast warning
+#pragma warning (disable:4702)
+#endif
+
+//
+// Constants
+//
+const F32 BIRD_AUDIBLE_RADIUS = 32.0f;
+const F32 SIT_DISTANCE_FROM_TARGET = 0.25f;
+static const F32 LOGOUT_REPLY_TIME = 3.f; // Wait this long after LogoutReply before quitting.
+
+// Determine how quickly residents' scripts can issue question dialogs
+// Allow bursts of up to 5 dialogs in 10 seconds. 10*2=20 seconds recovery if throttle kicks in
+static const U32 LLREQUEST_PERMISSION_THROTTLE_LIMIT = 5; // requests
+static const F32 LLREQUEST_PERMISSION_THROTTLE_INTERVAL = 10.0f; // seconds
+
+extern BOOL gDebugClicks;
+
+// function prototypes
+bool check_offer_throttle(const std::string& from_name, bool check_only);
+static void process_money_balance_reply_extended(LLMessageSystem* msg);
+
+//inventory offer throttle globals
+LLFrameTimer gThrottleTimer;
+const U32 OFFER_THROTTLE_MAX_COUNT=5; //number of items per time period
+const F32 OFFER_THROTTLE_TIME=10.f; //time period in seconds
+
+//script permissions
+const std::string SCRIPT_QUESTIONS[SCRIPT_PERMISSION_EOF] =
+ {
+ "ScriptTakeMoney",
+ "ActOnControlInputs",
+ "RemapControlInputs",
+ "AnimateYourAvatar",
+ "AttachToYourAvatar",
+ "ReleaseOwnership",
+ "LinkAndDelink",
+ "AddAndRemoveJoints",
+ "ChangePermissions",
+ "TrackYourCamera",
+ "ControlYourCamera"
+ };
+
+const BOOL SCRIPT_QUESTION_IS_CAUTION[SCRIPT_PERMISSION_EOF] =
+{
+ TRUE, // ScriptTakeMoney,
+ FALSE, // ActOnControlInputs
+ FALSE, // RemapControlInputs
+ FALSE, // AnimateYourAvatar
+ FALSE, // AttachToYourAvatar
+ FALSE, // ReleaseOwnership,
+ FALSE, // LinkAndDelink,
+ FALSE, // AddAndRemoveJoints
+ FALSE, // ChangePermissions
+ FALSE, // TrackYourCamera,
+ FALSE // ControlYourCamera
+};
+
+bool friendship_offer_callback(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ LLMessageSystem* msg = gMessageSystem;
+ const LLSD& payload = notification["payload"];
+
+ // add friend to recent people list
+ LLRecentPeople::instance().add(payload["from_id"]);
+
+ switch(option)
+ {
+ case 0:
+ {
+ // accept
+ LLAvatarTracker::formFriendship(payload["from_id"]);
+
+ const LLUUID fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD);
+
+ // This will also trigger an onlinenotification if the user is online
+ msg->newMessageFast(_PREHASH_AcceptFriendship);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_TransactionBlock);
+ msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]);
+ msg->nextBlockFast(_PREHASH_FolderData);
+ msg->addUUIDFast(_PREHASH_FolderID, fid);
+ msg->sendReliable(LLHost(payload["sender"].asString()));
+
+ LLSD payload = notification["payload"];
+ payload["SUPPRESS_TOAST"] = true;
+ LLNotificationsUtil::add("FriendshipAcceptedByMe",
+ notification["substitutions"], payload);
+ break;
+ }
+ case 1: // Decline
+ {
+ LLSD payload = notification["payload"];
+ payload["SUPPRESS_TOAST"] = true;
+ LLNotificationsUtil::add("FriendshipDeclinedByMe",
+ notification["substitutions"], payload);
+ }
+ // fall-through
+ case 2: // Send IM - decline and start IM session
+ {
+ // decline
+ // We no longer notify other viewers, but we DO still send
+ // the rejection to the simulator to delete the pending userop.
+ msg->newMessageFast(_PREHASH_DeclineFriendship);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_TransactionBlock);
+ msg->addUUIDFast(_PREHASH_TransactionID, payload["session_id"]);
+ msg->sendReliable(LLHost(payload["sender"].asString()));
+
+ // start IM session
+ if(2 == option)
+ {
+ LLAvatarActions::startIM(payload["from_id"].asUUID());
+ }
+ }
+ default:
+ // close button probably, possibly timed out
+ break;
+ }
+
+ return false;
+}
+static LLNotificationFunctorRegistration friendship_offer_callback_reg("OfferFriendship", friendship_offer_callback);
+static LLNotificationFunctorRegistration friendship_offer_callback_reg_nm("OfferFriendshipNoMessage", friendship_offer_callback);
+
+//const char BUSY_AUTO_RESPONSE[] = "The Resident you messaged is in 'busy mode' which means they have "
+// "requested not to be disturbed. Your message will still be shown in their IM "
+// "panel for later viewing.";
+
+//
+// Functions
+//
+
+void give_money(const LLUUID& uuid, LLViewerRegion* region, S32 amount, BOOL is_group,
+ S32 trx_type, const std::string& desc)
+{
+ if(0 == amount || !region) return;
+ amount = abs(amount);
+ LL_INFOS("Messaging") << "give_money(" << uuid << "," << amount << ")"<< LL_ENDL;
+ if(can_afford_transaction(amount))
+ {
+// gStatusBar->debitBalance(amount);
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_MoneyTransferRequest);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_MoneyData);
+ msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID() );
+ msg->addUUIDFast(_PREHASH_DestID, uuid);
+ msg->addU8Fast(_PREHASH_Flags, pack_transaction_flags(FALSE, is_group));
+ msg->addS32Fast(_PREHASH_Amount, amount);
+ msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY);
+ msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY);
+ msg->addS32Fast(_PREHASH_TransactionType, trx_type );
+ msg->addStringFast(_PREHASH_Description, desc);
+ msg->sendReliable(region->getHost());
+ }
+ else
+ {
+ LLStringUtil::format_map_t args;
+ args["AMOUNT"] = llformat("%d", amount);
+ LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("giving", args), amount );
+ }
+}
+
+void send_complete_agent_movement(const LLHost& sim_host)
+{
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_CompleteAgentMovement);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addU32Fast(_PREHASH_CircuitCode, msg->mOurCircuitCode);
+ msg->sendReliable(sim_host);
+}
+
+void process_logout_reply(LLMessageSystem* msg, void**)
+{
+ // The server has told us it's ok to quit.
+ LL_DEBUGS("Messaging") << "process_logout_reply" << LL_ENDL;
+
+ LLUUID agent_id;
+ msg->getUUID("AgentData", "AgentID", agent_id);
+ LLUUID session_id;
+ msg->getUUID("AgentData", "SessionID", session_id);
+ if((agent_id != gAgent.getID()) || (session_id != gAgent.getSessionID()))
+ {
+ LL_WARNS("Messaging") << "Bogus Logout Reply" << LL_ENDL;
+ }
+
+ LLInventoryModel::update_map_t parents;
+ S32 count = msg->getNumberOfBlocksFast( _PREHASH_InventoryData );
+ for(S32 i = 0; i < count; ++i)
+ {
+ LLUUID item_id;
+ msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i);
+
+ if( (1 == count) && item_id.isNull() )
+ {
+ // Detect dummy item. Indicates an empty list.
+ break;
+ }
+
+ // We do not need to track the asset ids, just account for an
+ // updated inventory version.
+ LL_INFOS("Messaging") << "process_logout_reply itemID=" << item_id << LL_ENDL;
+ LLInventoryItem* item = gInventory.getItem( item_id );
+ if( item )
+ {
+ parents[item->getParentUUID()] = 0;
+ gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id);
+ }
+ else
+ {
+ LL_INFOS("Messaging") << "process_logout_reply item not found: " << item_id << LL_ENDL;
+ }
+ }
+ LLAppViewer::instance()->forceQuit();
+}
+
+void process_layer_data(LLMessageSystem *mesgsys, void **user_data)
+{
+ LLViewerRegion *regionp = LLWorld::getInstance()->getRegion(mesgsys->getSender());
+
+ if (!regionp || gNoRender)
+ {
+ return;
+ }
+
+
+ S32 size;
+ S8 type;
+
+ mesgsys->getS8Fast(_PREHASH_LayerID, _PREHASH_Type, type);
+ size = mesgsys->getSizeFast(_PREHASH_LayerData, _PREHASH_Data);
+ if (0 == size)
+ {
+ LL_WARNS("Messaging") << "Layer data has zero size." << LL_ENDL;
+ return;
+ }
+ if (size < 0)
+ {
+ // getSizeFast() is probably trying to tell us about an error
+ LL_WARNS("Messaging") << "getSizeFast() returned negative result: "
+ << size
+ << LL_ENDL;
+ return;
+ }
+ U8 *datap = new U8[size];
+ mesgsys->getBinaryDataFast(_PREHASH_LayerData, _PREHASH_Data, datap, size);
+ LLVLData *vl_datap = new LLVLData(regionp, type, datap, size);
+ if (mesgsys->getReceiveCompressedSize())
+ {
+ gVLManager.addLayerData(vl_datap, mesgsys->getReceiveCompressedSize());
+ }
+ else
+ {
+ gVLManager.addLayerData(vl_datap, mesgsys->getReceiveSize());
+ }
+}
+
+// S32 exported_object_count = 0;
+// S32 exported_image_count = 0;
+// S32 current_object_count = 0;
+// S32 current_image_count = 0;
+
+// extern LLNotifyBox *gExporterNotify;
+// extern LLUUID gExporterRequestID;
+// extern std::string gExportDirectory;
+
+// extern LLUploadDialog *gExportDialog;
+
+// std::string gExportedFile;
+
+// std::map<LLUUID, std::string> gImageChecksums;
+
+// void export_complete()
+// {
+// LLUploadDialog::modalUploadFinished();
+// gExporterRequestID.setNull();
+// gExportDirectory = "";
+
+// LLFILE* fXML = LLFile::fopen(gExportedFile, "rb"); /* Flawfinder: ignore */
+// fseek(fXML, 0, SEEK_END);
+// long length = ftell(fXML);
+// fseek(fXML, 0, SEEK_SET);
+// U8 *buffer = new U8[length + 1];
+// size_t nread = fread(buffer, 1, length, fXML);
+// if (nread < (size_t) length)
+// {
+// LL_WARNS("Messaging") << "Short read" << LL_ENDL;
+// }
+// buffer[nread] = '\0';
+// fclose(fXML);
+
+// char *pos = (char *)buffer;
+// while ((pos = strstr(pos+1, "<sl:image ")) != 0)
+// {
+// char *pos_check = strstr(pos, "checksum=\"");
+
+// if (pos_check)
+// {
+// char *pos_uuid = strstr(pos_check, "\">");
+
+// if (pos_uuid)
+// {
+// char image_uuid_str[UUID_STR_SIZE]; /* Flawfinder: ignore */
+// memcpy(image_uuid_str, pos_uuid+2, UUID_STR_SIZE-1); /* Flawfinder: ignore */
+// image_uuid_str[UUID_STR_SIZE-1] = 0;
+
+// LLUUID image_uuid(image_uuid_str);
+
+// LL_INFOS("Messaging") << "Found UUID: " << image_uuid << LL_ENDL;
+
+// std::map<LLUUID, std::string>::iterator itor = gImageChecksums.find(image_uuid);
+// if (itor != gImageChecksums.end())
+// {
+// LL_INFOS("Messaging") << "Replacing with checksum: " << itor->second << LL_ENDL;
+// if (!itor->second.empty())
+// {
+// memcpy(&pos_check[10], itor->second.c_str(), 32); /* Flawfinder: ignore */
+// }
+// }
+// }
+// }
+// }
+
+// LLFILE* fXMLOut = LLFile::fopen(gExportedFile, "wb"); /* Flawfinder: ignore */
+// if (fwrite(buffer, 1, length, fXMLOut) != length)
+// {
+// LL_WARNS("Messaging") << "Short write" << LL_ENDL;
+// }
+// fclose(fXMLOut);
+
+// delete [] buffer;
+// }
+
+
+// void exported_item_complete(const LLTSCode status, void *user_data)
+// {
+// //std::string *filename = (std::string *)user_data;
+
+// if (status < LLTS_OK)
+// {
+// LL_WARNS("Messaging") << "Export failed!" << LL_ENDL;
+// }
+// else
+// {
+// ++current_object_count;
+// if (current_image_count == exported_image_count && current_object_count == exported_object_count)
+// {
+// LL_INFOS("Messaging") << "*** Export complete ***" << LL_ENDL;
+
+// export_complete();
+// }
+// else
+// {
+// gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count));
+// }
+// }
+// }
+
+// struct exported_image_info
+// {
+// LLUUID image_id;
+// std::string filename;
+// U32 image_num;
+// };
+
+// void exported_j2c_complete(const LLTSCode status, void *user_data)
+// {
+// exported_image_info *info = (exported_image_info *)user_data;
+// LLUUID image_id = info->image_id;
+// U32 image_num = info->image_num;
+// std::string filename = info->filename;
+// delete info;
+
+// if (status < LLTS_OK)
+// {
+// LL_WARNS("Messaging") << "Image download failed!" << LL_ENDL;
+// }
+// else
+// {
+// LLFILE* fIn = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */
+// if (fIn)
+// {
+// LLPointer<LLImageJ2C> ImageUtility = new LLImageJ2C;
+// LLPointer<LLImageTGA> TargaUtility = new LLImageTGA;
+
+// fseek(fIn, 0, SEEK_END);
+// S32 length = ftell(fIn);
+// fseek(fIn, 0, SEEK_SET);
+// U8 *buffer = ImageUtility->allocateData(length);
+// if (fread(buffer, 1, length, fIn) != length)
+// {
+// LL_WARNS("Messaging") << "Short read" << LL_ENDL;
+// }
+// fclose(fIn);
+// LLFile::remove(filename);
+
+// // Convert to TGA
+// LLPointer<LLImageRaw> image = new LLImageRaw();
+
+// ImageUtility->updateData();
+// ImageUtility->decode(image, 100000.0f);
+
+// TargaUtility->encode(image);
+// U8 *data = TargaUtility->getData();
+// S32 data_size = TargaUtility->getDataSize();
+
+// std::string file_path = gDirUtilp->getDirName(filename);
+
+// std::string output_file = llformat("%s/image-%03d.tga", file_path.c_str(), image_num);//filename;
+// //S32 name_len = output_file.length();
+// //strcpy(&output_file[name_len-3], "tga");
+// LLFILE* fOut = LLFile::fopen(output_file, "wb"); /* Flawfinder: ignore */
+// char md5_hash_string[33]; /* Flawfinder: ignore */
+// strcpy(md5_hash_string, "00000000000000000000000000000000"); /* Flawfinder: ignore */
+// if (fOut)
+// {
+// if (fwrite(data, 1, data_size, fOut) != data_size)
+// {
+// LL_WARNS("Messaging") << "Short write" << LL_ENDL;
+// }
+// fseek(fOut, 0, SEEK_SET);
+// fclose(fOut);
+// fOut = LLFile::fopen(output_file, "rb"); /* Flawfinder: ignore */
+// LLMD5 my_md5_hash(fOut);
+// my_md5_hash.hex_digest(md5_hash_string);
+// }
+
+// gImageChecksums.insert(std::pair<LLUUID, std::string>(image_id, md5_hash_string));
+// }
+// }
+
+// ++current_image_count;
+// if (current_image_count == exported_image_count && current_object_count == exported_object_count)
+// {
+// LL_INFOS("Messaging") << "*** Export textures complete ***" << LL_ENDL;
+// export_complete();
+// }
+// else
+// {
+// gExportDialog->setMessage(llformat("Exported %d/%d object files, %d/%d textures.", current_object_count, exported_object_count, current_image_count, exported_image_count));
+// }
+//}
+
+void process_derez_ack(LLMessageSystem*, void**)
+{
+ if(gViewerWindow) gViewerWindow->getWindow()->decBusyCount();
+}
+
+void process_places_reply(LLMessageSystem* msg, void** data)
+{
+ LLUUID query_id;
+
+ msg->getUUID("AgentData", "QueryID", query_id);
+ if (query_id.isNull())
+ {
+ LLFloaterLandHoldings::processPlacesReply(msg, data);
+ }
+ else if(gAgent.isInGroup(query_id))
+ {
+ LLPanelGroupLandMoney::processPlacesReply(msg, data);
+ }
+ else
+ {
+ LL_WARNS("Messaging") << "Got invalid PlacesReply message" << LL_ENDL;
+ }
+}
+
+void send_sound_trigger(const LLUUID& sound_id, F32 gain)
+{
+ if (sound_id.isNull() || gAgent.getRegion() == NULL)
+ {
+ // disconnected agent or zero guids don't get sent (no sound)
+ return;
+ }
+
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_SoundTrigger);
+ msg->nextBlockFast(_PREHASH_SoundData);
+ msg->addUUIDFast(_PREHASH_SoundID, sound_id);
+ // Client untrusted, ids set on sim
+ msg->addUUIDFast(_PREHASH_OwnerID, LLUUID::null );
+ msg->addUUIDFast(_PREHASH_ObjectID, LLUUID::null );
+ msg->addUUIDFast(_PREHASH_ParentID, LLUUID::null );
+
+ msg->addU64Fast(_PREHASH_Handle, gAgent.getRegion()->getHandle());
+
+ LLVector3 position = gAgent.getPositionAgent();
+ msg->addVector3Fast(_PREHASH_Position, position);
+ msg->addF32Fast(_PREHASH_Gain, gain);
+
+ gAgent.sendMessage();
+}
+
+bool join_group_response(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ BOOL delete_context_data = TRUE;
+ bool accept_invite = false;
+
+ LLUUID group_id = notification["payload"]["group_id"].asUUID();
+ LLUUID transaction_id = notification["payload"]["transaction_id"].asUUID();
+ std::string name = notification["payload"]["name"].asString();
+ std::string message = notification["payload"]["message"].asString();
+ S32 fee = notification["payload"]["fee"].asInteger();
+
+ if (option == 2 && !group_id.isNull())
+ {
+ LLGroupActions::show(group_id);
+ LLSD args;
+ args["MESSAGE"] = message;
+ LLNotificationsUtil::add("JoinGroup", args, notification["payload"]);
+ return false;
+ }
+ if(option == 0 && !group_id.isNull())
+ {
+ // check for promotion or demotion.
+ S32 max_groups = gMaxAgentGroups;
+ if(gAgent.isInGroup(group_id)) ++max_groups;
+
+ if(gAgent.mGroups.count() < max_groups)
+ {
+ accept_invite = true;
+ }
+ else
+ {
+ delete_context_data = FALSE;
+ LLSD args;
+ args["NAME"] = name;
+ LLNotificationsUtil::add("JoinedTooManyGroupsMember", args, notification["payload"]);
+ }
+ }
+
+ if (accept_invite)
+ {
+ // If there is a fee to join this group, make
+ // sure the user is sure they want to join.
+ if (fee > 0)
+ {
+ delete_context_data = FALSE;
+ LLSD args;
+ args["COST"] = llformat("%d", fee);
+ // Set the fee for next time to 0, so that we don't keep
+ // asking about a fee.
+ LLSD next_payload = notification["payload"];
+ next_payload["fee"] = 0;
+ LLNotificationsUtil::add("JoinGroupCanAfford",
+ args,
+ next_payload);
+ }
+ else
+ {
+ send_improved_im(group_id,
+ std::string("name"),
+ std::string("message"),
+ IM_ONLINE,
+ IM_GROUP_INVITATION_ACCEPT,
+ transaction_id);
+ }
+ }
+ else
+ {
+ send_improved_im(group_id,
+ std::string("name"),
+ std::string("message"),
+ IM_ONLINE,
+ IM_GROUP_INVITATION_DECLINE,
+ transaction_id);
+ }
+
+ return false;
+}
+
+static void highlight_inventory_items_in_panel(const std::vector<LLUUID>& items, LLInventoryPanel *inventory_panel)
+{
+ if (NULL == inventory_panel) return;
+
+ for (std::vector<LLUUID>::const_iterator item_iter = items.begin();
+ item_iter != items.end();
+ ++item_iter)
+ {
+ const LLUUID& item_id = (*item_iter);
+ if(!highlight_offered_object(item_id))
+ {
+ continue;
+ }
+
+ LLInventoryItem* item = gInventory.getItem(item_id);
+ llassert(item);
+ if (!item) {
+ continue;
+ }
+
+ LL_DEBUGS("Inventory_Move") << "Highlighting inventory item: " << item->getName() << ", " << item_id << LL_ENDL;
+ LLFolderView* fv = inventory_panel->getRootFolder();
+ if (fv)
+ {
+ LLFolderViewItem* fv_item = fv->getItemByID(item_id);
+ if (fv_item)
+ {
+ LLFolderViewItem* fv_folder = fv_item->getParentFolder();
+ if (fv_folder)
+ {
+ // Parent folders can be different in case of 2 consecutive drag and drop
+ // operations when the second one is started before the first one completes.
+ LL_DEBUGS("Inventory_Move") << "Open folder: " << fv_folder->getName() << LL_ENDL;
+ fv_folder->setOpen(TRUE);
+ if (fv_folder->isSelected())
+ {
+ fv->changeSelection(fv_folder, FALSE);
+ }
+ }
+ fv->changeSelection(fv_item, TRUE);
+ }
+ }
+ }
+}
+
+static LLNotificationFunctorRegistration jgr_1("JoinGroup", join_group_response);
+static LLNotificationFunctorRegistration jgr_2("JoinedTooManyGroupsMember", join_group_response);
+static LLNotificationFunctorRegistration jgr_3("JoinGroupCanAfford", join_group_response);
+
+
+//-----------------------------------------------------------------------------
+// Instant Message
+//-----------------------------------------------------------------------------
+class LLOpenAgentOffer : public LLInventoryFetchItemsObserver
+{
+public:
+ LLOpenAgentOffer(const LLUUID& object_id,
+ const std::string& from_name) :
+ LLInventoryFetchItemsObserver(object_id),
+ mFromName(from_name) {}
+ /*virtual*/ void startFetch()
+ {
+ for (uuid_vec_t::const_iterator it = mIDs.begin(); it < mIDs.end(); ++it)
+ {
+ LLViewerInventoryCategory* cat = gInventory.getCategory(*it);
+ if (cat)
+ {
+ mComplete.push_back((*it));
+ }
+ }
+ LLInventoryFetchItemsObserver::startFetch();
+ }
+ /*virtual*/ void done()
+ {
+ open_inventory_offer(mComplete, mFromName);
+ gInventory.removeObserver(this);
+ delete this;
+ }
+private:
+ std::string mFromName;
+};
+
+/**
+ * Class to observe adding of new items moved from the world to user's inventory to select them in inventory.
+ *
+ * We can't create it each time items are moved because "drop" event is sent separately for each
+ * element even while multi-dragging. We have to have the only instance of the observer. See EXT-4347.
+ */
+class LLViewerInventoryMoveFromWorldObserver : public LLInventoryAddItemByAssetObserver
+{
+public:
+ LLViewerInventoryMoveFromWorldObserver()
+ : LLInventoryAddItemByAssetObserver()
+ , mActivePanel(NULL)
+ {
+
+ }
+
+ void setMoveIntoFolderID(const LLUUID& into_folder_uuid) {mMoveIntoFolderID = into_folder_uuid; }
+
+private:
+ /*virtual */void onAssetAdded(const LLUUID& asset_id)
+ {
+ // Store active Inventory panel.
+ mActivePanel = LLInventoryPanel::getActiveInventoryPanel();
+
+ // Store selected items (without destination folder)
+ mSelectedItems.clear();
+ if (mActivePanel)
+ {
+ mSelectedItems = mActivePanel->getRootFolder()->getSelectionList();
+ }
+ mSelectedItems.erase(mMoveIntoFolderID);
+ }
+
+ /**
+ * Selects added inventory items watched by their Asset UUIDs if selection was not changed since
+ * all items were started to watch (dropped into a folder).
+ */
+ void done()
+ {
+ // if selection is not changed since watch started lets hightlight new items.
+ if (mActivePanel && !isSelectionChanged())
+ {
+ LL_DEBUGS("Inventory_Move") << "Selecting new items..." << LL_ENDL;
+ mActivePanel->clearSelection();
+ highlight_inventory_items_in_panel(mAddedItems, mActivePanel);
+ }
+ }
+
+ /**
+ * Returns true if selected inventory items were changed since moved inventory items were started to watch.
+ */
+ bool isSelectionChanged()
+ {
+ const LLInventoryPanel * const current_active_panel = LLInventoryPanel::getActiveInventoryPanel();
+
+ if (NULL == mActivePanel || current_active_panel != mActivePanel)
+ {
+ return true;
+ }
+
+ // get selected items (without destination folder)
+ selected_items_t selected_items = mActivePanel->getRootFolder()->getSelectionList();
+ selected_items.erase(mMoveIntoFolderID);
+
+ // compare stored & current sets of selected items
+ selected_items_t different_items;
+ std::set_symmetric_difference(mSelectedItems.begin(), mSelectedItems.end(),
+ selected_items.begin(), selected_items.end(), std::inserter(different_items, different_items.begin()));
+
+ LL_DEBUGS("Inventory_Move") << "Selected firstly: " << mSelectedItems.size()
+ << ", now: " << selected_items.size() << ", difference: " << different_items.size() << LL_ENDL;
+
+ return different_items.size() > 0;
+ }
+
+ LLInventoryPanel *mActivePanel;
+ typedef std::set<LLUUID> selected_items_t;
+ selected_items_t mSelectedItems;
+
+ /**
+ * UUID of FolderViewFolder into which watched items are moved.
+ *
+ * Destination FolderViewFolder becomes selected while mouse hovering (when dragged items are dropped).
+ *
+ * If mouse is moved out it set unselected and number of selected items is changed
+ * even if selected items in Inventory stay the same.
+ * So, it is used to update stored selection list.
+ *
+ * @see onAssetAdded()
+ * @see isSelectionChanged()
+ */
+ LLUUID mMoveIntoFolderID;
+};
+
+LLViewerInventoryMoveFromWorldObserver* gInventoryMoveObserver = NULL;
+
+void set_dad_inventory_item(LLInventoryItem* inv_item, const LLUUID& into_folder_uuid)
+{
+ start_new_inventory_observer();
+
+ gInventoryMoveObserver->setMoveIntoFolderID(into_folder_uuid);
+ gInventoryMoveObserver->watchAsset(inv_item->getAssetUUID());
+}
+
+//unlike the FetchObserver for AgentOffer, we only make one
+//instance of the AddedObserver for TaskOffers
+//and it never dies. We do this because we don't know the UUID of
+//task offers until they are accepted, so we don't wouldn't
+//know what to watch for, so instead we just watch for all additions.
+class LLOpenTaskOffer : public LLInventoryAddedObserver
+{
+protected:
+ /*virtual*/ void done()
+ {
+ for (uuid_vec_t::iterator it = mAdded.begin(); it != mAdded.end();)
+ {
+ const LLUUID& item_uuid = *it;
+ bool was_moved = false;
+ LLInventoryObject* added_object = gInventory.getObject(item_uuid);
+ if (added_object)
+ {
+ // cast to item to get Asset UUID
+ LLInventoryItem* added_item = dynamic_cast<LLInventoryItem*>(added_object);
+ if (added_item)
+ {
+ const LLUUID& asset_uuid = added_item->getAssetUUID();
+ if (gInventoryMoveObserver->isAssetWatched(asset_uuid))
+ {
+ LL_DEBUGS("Inventory_Move") << "Found asset UUID: " << asset_uuid << LL_ENDL;
+ was_moved = true;
+ }
+ }
+ }
+
+ if (was_moved)
+ {
+ it = mAdded.erase(it);
+ }
+ else ++it;
+ }
+
+ open_inventory_offer(mAdded, "");
+ mAdded.clear();
+ }
+ };
+
+class LLOpenTaskGroupOffer : public LLInventoryAddedObserver
+{
+protected:
+ /*virtual*/ void done()
+ {
+ open_inventory_offer(mAdded, "group_offer");
+ mAdded.clear();
+ gInventory.removeObserver(this);
+ delete this;
+ }
+};
+
+//one global instance to bind them
+LLOpenTaskOffer* gNewInventoryObserver=NULL;
+
+class LLNewInventoryHintObserver : public LLInventoryAddedObserver
+{
+protected:
+ /*virtual*/ void done()
+ {
+ LLFirstUse::newInventory();
+ }
+};
+
+void start_new_inventory_observer()
+{
+ if (!gNewInventoryObserver) //task offer observer
+ {
+ // Observer is deleted by gInventory
+ gNewInventoryObserver = new LLOpenTaskOffer;
+ gInventory.addObserver(gNewInventoryObserver);
+ }
+
+ if (!gInventoryMoveObserver) //inventory move from the world observer
+ {
+ // Observer is deleted by gInventory
+ gInventoryMoveObserver = new LLViewerInventoryMoveFromWorldObserver;
+ gInventory.addObserver(gInventoryMoveObserver);
+ }
+
+ gInventory.addObserver(new LLNewInventoryHintObserver());
+}
+
+class LLDiscardAgentOffer : public LLInventoryFetchItemsObserver
+{
+ LOG_CLASS(LLDiscardAgentOffer);
+public:
+ LLDiscardAgentOffer(const LLUUID& folder_id, const LLUUID& object_id) :
+ LLInventoryFetchItemsObserver(object_id),
+ mFolderID(folder_id),
+ mObjectID(object_id) {}
+ virtual ~LLDiscardAgentOffer() {}
+ virtual void done()
+ {
+ LL_DEBUGS("Messaging") << "LLDiscardAgentOffer::done()" << LL_ENDL;
+ const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ bool notify = false;
+ if(trash_id.notNull() && mObjectID.notNull())
+ {
+ LLInventoryModel::update_list_t update;
+ LLInventoryModel::LLCategoryUpdate old_folder(mFolderID, -1);
+ update.push_back(old_folder);
+ LLInventoryModel::LLCategoryUpdate new_folder(trash_id, 1);
+ update.push_back(new_folder);
+ gInventory.accountForUpdate(update);
+ gInventory.moveObject(mObjectID, trash_id);
+ LLInventoryObject* obj = gInventory.getObject(mObjectID);
+ if(obj)
+ {
+ // no need to restamp since this is already a freshly
+ // stamped item.
+ obj->updateParentOnServer(FALSE);
+ notify = true;
+ }
+ }
+ else
+ {
+ LL_WARNS("Messaging") << "DiscardAgentOffer unable to find: "
+ << (trash_id.isNull() ? "trash " : "")
+ << (mObjectID.isNull() ? "object" : "") << LL_ENDL;
+ }
+ gInventory.removeObserver(this);
+ if(notify)
+ {
+ gInventory.notifyObservers();
+ }
+ delete this;
+ }
+protected:
+ LLUUID mFolderID;
+ LLUUID mObjectID;
+};
+
+
+//Returns TRUE if we are OK, FALSE if we are throttled
+//Set check_only true if you want to know the throttle status
+//without registering a hit
+bool check_offer_throttle(const std::string& from_name, bool check_only)
+{
+ static U32 throttle_count;
+ static bool throttle_logged;
+ LLChat chat;
+ std::string log_message;
+
+ if (!gSavedSettings.getBOOL("ShowNewInventory"))
+ return false;
+
+ if (check_only)
+ {
+ return gThrottleTimer.hasExpired();
+ }
+
+ if(gThrottleTimer.checkExpirationAndReset(OFFER_THROTTLE_TIME))
+ {
+ LL_DEBUGS("Messaging") << "Throttle Expired" << LL_ENDL;
+ throttle_count=1;
+ throttle_logged=false;
+ return true;
+ }
+ else //has not expired
+ {
+ LL_DEBUGS("Messaging") << "Throttle Not Expired, Count: " << throttle_count << LL_ENDL;
+ // When downloading the initial inventory we get a lot of new items
+ // coming in and can't tell that from spam.
+ if (LLStartUp::getStartupState() >= STATE_STARTED
+ && throttle_count >= OFFER_THROTTLE_MAX_COUNT)
+ {
+ if (!throttle_logged)
+ {
+ // Use the name of the last item giver, who is probably the person
+ // spamming you.
+
+ LLStringUtil::format_map_t arg;
+ std::string log_msg;
+ std::ostringstream time ;
+ time<<OFFER_THROTTLE_TIME;
+
+ arg["APP_NAME"] = LLAppViewer::instance()->getSecondLifeTitle();
+ arg["TIME"] = time.str();
+
+ if (!from_name.empty())
+ {
+ arg["FROM_NAME"] = from_name;
+ log_msg = LLTrans::getString("ItemsComingInTooFastFrom", arg);
+ }
+ else
+ {
+ log_msg = LLTrans::getString("ItemsComingInTooFast", arg);
+ }
+
+ //this is kinda important, so actually put it on screen
+ LLSD args;
+ args["MESSAGE"] = log_msg;
+ LLNotificationsUtil::add("SystemMessage", args);
+
+ throttle_logged=true;
+ }
+ return false;
+ }
+ else
+ {
+ throttle_count++;
+ return true;
+ }
+ }
+}
+
+void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_name)
+{
+ for (uuid_vec_t::const_iterator obj_iter = objects.begin();
+ obj_iter != objects.end();
+ ++obj_iter)
+ {
+ const LLUUID& obj_id = (*obj_iter);
+ if(!highlight_offered_object(obj_id))
+ {
+ continue;
+ }
+
+ const LLInventoryObject *obj = gInventory.getObject(obj_id);
+ if (!obj)
+ {
+ llwarns << "Cannot find object [ itemID:" << obj_id << " ] to open." << llendl;
+ continue;
+ }
+
+ const LLAssetType::EType asset_type = obj->getActualType();
+
+ // Either an inventory item or a category.
+ const LLInventoryItem* item = dynamic_cast<const LLInventoryItem*>(obj);
+ if (item)
+ {
+ ////////////////////////////////////////////////////////////////////////////////
+ // Special handling for various types.
+ if (check_offer_throttle(from_name, false)) // If we are throttled, don't display
+ {
+ LL_DEBUGS("Messaging") << "Highlighting inventory item: " << item->getUUID() << LL_ENDL;
+ // If we opened this ourselves, focus it
+ const BOOL take_focus = from_name.empty() ? TAKE_FOCUS_YES : TAKE_FOCUS_NO;
+ switch(asset_type)
+ {
+ case LLAssetType::AT_NOTECARD:
+ {
+ LLFloaterReg::showInstance("preview_notecard", LLSD(obj_id), take_focus);
+ break;
+ }
+ case LLAssetType::AT_LANDMARK:
+ {
+ LLInventoryCategory* parent_folder = gInventory.getCategory(item->getParentUUID());
+ if ("inventory_handler" == from_name)
+ {
+ //we have to filter inventory_handler messages to avoid notification displaying
+ LLSideTray::getInstance()->showPanel("panel_places",
+ LLSD().with("type", "landmark").with("id", item->getUUID()));
+ }
+ else if("group_offer" == from_name)
+ {
+ // "group_offer" is passed by LLOpenTaskGroupOffer
+ // Notification about added landmark will be generated under the "from_name.empty()" called from LLOpenTaskOffer::done().
+ LLSD args;
+ args["type"] = "landmark";
+ args["id"] = obj_id;
+ LLSideTray::getInstance()->showPanel("panel_places", args);
+
+ continue;
+ }
+ else if(from_name.empty())
+ {
+ std::string folder_name;
+ if (parent_folder)
+ {
+ // Localize folder name.
+ // *TODO: share this code?
+ folder_name = parent_folder->getName();
+ if (LLFolderType::lookupIsProtectedType(parent_folder->getPreferredType()))
+ {
+ LLTrans::findString(folder_name, "InvFolder " + folder_name);
+ }
+ }
+ else
+ {
+ folder_name = LLTrans::getString("Unknown");
+ }
+
+ // we receive a message from LLOpenTaskOffer, it mean that new landmark has been added.
+ LLSD args;
+ args["LANDMARK_NAME"] = item->getName();
+ args["FOLDER_NAME"] = folder_name;
+ LLNotificationsUtil::add("LandmarkCreated", args);
+ }
+ }
+ break;
+ case LLAssetType::AT_TEXTURE:
+ {
+ LLFloaterReg::showInstance("preview_texture", LLSD(obj_id), take_focus);
+ break;
+ }
+ case LLAssetType::AT_ANIMATION:
+ LLFloaterReg::showInstance("preview_anim", LLSD(obj_id), take_focus);
+ break;
+ case LLAssetType::AT_SCRIPT:
+ LLFloaterReg::showInstance("preview_script", LLSD(obj_id), take_focus);
+ break;
+ case LLAssetType::AT_SOUND:
+ LLFloaterReg::showInstance("preview_sound", LLSD(obj_id), take_focus);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Highlight item
+ const BOOL auto_open =
+ gSavedSettings.getBOOL("ShowInInventory") && // don't open if showininventory is false
+ !from_name.empty(); // don't open if it's not from anyone.
+ LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(auto_open);
+ if(active_panel)
+ {
+ LL_DEBUGS("Messaging") << "Highlighting" << obj_id << LL_ENDL;
+ LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus();
+ active_panel->setSelection(obj_id, TAKE_FOCUS_NO);
+ gFocusMgr.setKeyboardFocus(focus_ctrl);
+ }
+ }
+}
+
+bool highlight_offered_object(const LLUUID& obj_id)
+{
+ const LLInventoryObject* obj = gInventory.getObject(obj_id);
+ if(!obj)
+ {
+ LL_WARNS("Messaging") << "Unable to show inventory item: " << obj_id << LL_ENDL;
+ return false;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////
+ // Don't highlight if it's in certain "quiet" folders which don't need UI
+ // notification (e.g. trash, cof, lost-and-found).
+ if(!gAgent.getAFK())
+ {
+ const LLViewerInventoryCategory *parent = gInventory.getFirstNondefaultParent(obj_id);
+ if (parent)
+ {
+ const LLFolderType::EType parent_type = parent->getPreferredType();
+ if (LLViewerFolderType::lookupIsQuietType(parent_type))
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+void inventory_offer_mute_callback(const LLUUID& blocked_id,
+ const std::string& full_name,
+ bool is_group,
+ boost::shared_ptr<LLNotificationResponderInterface> offer_ptr)
+{
+ LLOfferInfo* offer = dynamic_cast<LLOfferInfo*>(offer_ptr.get());
+
+ std::string from_name = full_name;
+ LLMute::EType type;
+ if (is_group)
+ {
+ type = LLMute::GROUP;
+ }
+ else if(offer && offer->mFromObject)
+ {
+ //we have to block object by name because blocked_id is an id of owner
+ type = LLMute::BY_NAME;
+ }
+ else
+ {
+ type = LLMute::AGENT;
+ }
+
+ // id should be null for BY_NAME mute, see LLMuteList::add for details
+ LLMute mute(type == LLMute::BY_NAME ? LLUUID::null : blocked_id, from_name, type);
+ if (LLMuteList::getInstance()->add(mute))
+ {
+ LLPanelBlockedList::showPanelAndSelect(blocked_id);
+ }
+
+ // purge the message queue of any previously queued inventory offers from the same source.
+ class OfferMatcher : public LLNotificationsUI::LLScreenChannel::Matcher
+ {
+ public:
+ OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {}
+ bool matches(const LLNotificationPtr notification) const
+ {
+ if(notification->getName() == "ObjectGiveItem"
+ || notification->getName() == "UserGiveItem")
+ {
+ return (notification->getPayload()["from_id"].asUUID() == blocked_id);
+ }
+ return FALSE;
+ }
+ private:
+ const LLUUID& blocked_id;
+ };
+
+ LLNotificationsUI::LLChannelManager::getInstance()->killToastsFromChannel(LLUUID(
+ gSavedSettings.getString("NotificationChannelUUID")), OfferMatcher(blocked_id));
+}
+
+LLOfferInfo::LLOfferInfo()
+ : LLNotificationResponderInterface()
+ , mFromGroup(FALSE)
+ , mFromObject(FALSE)
+ , mIM(IM_NOTHING_SPECIAL)
+ , mType(LLAssetType::AT_NONE)
+ , mPersist(false)
+{
+}
+
+LLOfferInfo::LLOfferInfo(const LLSD& sd)
+{
+ mIM = (EInstantMessage)sd["im_type"].asInteger();
+ mFromID = sd["from_id"].asUUID();
+ mFromGroup = sd["from_group"].asBoolean();
+ mFromObject = sd["from_object"].asBoolean();
+ mTransactionID = sd["transaction_id"].asUUID();
+ mFolderID = sd["folder_id"].asUUID();
+ mObjectID = sd["object_id"].asUUID();
+ mType = LLAssetType::lookup(sd["type"].asString().c_str());
+ mFromName = sd["from_name"].asString();
+ mDesc = sd["description"].asString();
+ mHost = LLHost(sd["sender"].asString());
+ mPersist = sd["persist"].asBoolean();
+}
+
+LLOfferInfo::LLOfferInfo(const LLOfferInfo& info)
+{
+ mIM = info.mIM;
+ mFromID = info.mFromID;
+ mFromGroup = info.mFromGroup;
+ mFromObject = info.mFromObject;
+ mTransactionID = info.mTransactionID;
+ mFolderID = info.mFolderID;
+ mObjectID = info.mObjectID;
+ mType = info.mType;
+ mFromName = info.mFromName;
+ mDesc = info.mDesc;
+ mHost = info.mHost;
+ mPersist = info.mPersist;
+}
+
+LLSD LLOfferInfo::asLLSD()
+{
+ LLSD sd;
+ sd["im_type"] = mIM;
+ sd["from_id"] = mFromID;
+ sd["from_group"] = mFromGroup;
+ sd["from_object"] = mFromObject;
+ sd["transaction_id"] = mTransactionID;
+ sd["folder_id"] = mFolderID;
+ sd["object_id"] = mObjectID;
+ sd["type"] = LLAssetType::lookup(mType);
+ sd["from_name"] = mFromName;
+ sd["description"] = mDesc;
+ sd["sender"] = mHost.getIPandPort();
+ sd["persist"] = mPersist;
+ return sd;
+}
+
+void LLOfferInfo::fromLLSD(const LLSD& params)
+{
+ *this = params;
+}
+
+void LLOfferInfo::send_auto_receive_response(void)
+{
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_ImprovedInstantMessage);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_MessageBlock);
+ msg->addBOOLFast(_PREHASH_FromGroup, FALSE);
+ msg->addUUIDFast(_PREHASH_ToAgentID, mFromID);
+ msg->addU8Fast(_PREHASH_Offline, IM_ONLINE);
+ msg->addUUIDFast(_PREHASH_ID, mTransactionID);
+ msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary
+ std::string name;
+ LLAgentUI::buildFullname(name);
+ msg->addStringFast(_PREHASH_FromAgentName, name);
+ msg->addStringFast(_PREHASH_Message, "");
+ msg->addU32Fast(_PREHASH_ParentEstateID, 0);
+ msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null);
+ msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent());
+
+ // Auto Receive Message. The math for the dialog works, because the accept
+ // for inventory_offered, task_inventory_offer or
+ // group_notice_inventory is 1 greater than the offer integer value.
+ // Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED,
+ // or IM_GROUP_NOTICE_INVENTORY_ACCEPTED
+ msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1));
+ msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(mFolderID.mData),
+ sizeof(mFolderID.mData));
+ // send the message
+ msg->sendReliable(mHost);
+
+ if(IM_INVENTORY_OFFERED == mIM)
+ {
+ // add buddy to recent people list
+ LLRecentPeople::instance().add(mFromID);
+ }
+}
+
+void LLOfferInfo::handleRespond(const LLSD& notification, const LLSD& response)
+{
+ initRespondFunctionMap();
+
+ const std::string name = notification["name"].asString();
+ if(mRespondFunctions.find(name) == mRespondFunctions.end())
+ {
+ llwarns << "Unexpected notification name : " << name << llendl;
+ llassert(!"Unexpected notification name");
+ return;
+ }
+
+ mRespondFunctions[name](notification, response);
+}
+
+bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& response)
+{
+ LLChat chat;
+ std::string log_message;
+ S32 button = LLNotificationsUtil::getSelectedOption(notification, response);
+
+ LLInventoryObserver* opener = NULL;
+ LLViewerInventoryCategory* catp = NULL;
+ catp = (LLViewerInventoryCategory*)gInventory.getCategory(mObjectID);
+ LLViewerInventoryItem* itemp = NULL;
+ if(!catp)
+ {
+ itemp = (LLViewerInventoryItem*)gInventory.getItem(mObjectID);
+ }
+
+ // For muting, we need to add the mute, then decline the offer.
+ // This must be done here because:
+ // * callback may be called immediately,
+ // * adding the mute sends a message,
+ // * we can't build two messages at once.
+ if (2 == button) // Block
+ {
+ LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID());
+
+ llassert(notification_ptr != NULL);
+ if (notification_ptr != NULL)
+ {
+ gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback,_1,_2,_3,notification_ptr->getResponderPtr()));
+ }
+ }
+
+ std::string from_string; // Used in the pop-up.
+ std::string chatHistory_string; // Used in chat history.
+
+ // TODO: when task inventory offers can also be handled the new way, migrate the code that sets these strings here:
+ from_string = chatHistory_string = mFromName;
+
+ bool busy=FALSE;
+
+ switch(button)
+ {
+ case IOR_SHOW:
+ // we will want to open this item when it comes back.
+ LL_DEBUGS("Messaging") << "Initializing an opener for tid: " << mTransactionID
+ << LL_ENDL;
+ switch (mIM)
+ {
+ case IM_INVENTORY_OFFERED:
+ {
+ // This is an offer from an agent. In this case, the back
+ // end has already copied the items into your inventory,
+ // so we can fetch it out of our inventory.
+ if (gSavedSettings.getBOOL("ShowOfferedInventory"))
+ {
+ LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(mObjectID, from_string);
+ open_agent_offer->startFetch();
+ if(catp || (itemp && itemp->isFinished()))
+ {
+ open_agent_offer->done();
+ }
+ else
+ {
+ opener = open_agent_offer;
+ }
+ }
+ }
+ break;
+ case IM_GROUP_NOTICE:
+ opener = new LLOpenTaskGroupOffer;
+ send_auto_receive_response();
+ break;
+ case IM_TASK_INVENTORY_OFFERED:
+ case IM_GROUP_NOTICE_REQUESTED:
+ // This is an offer from a task or group.
+ // We don't use a new instance of an opener
+ // We instead use the singular observer gOpenTaskOffer
+ // Since it already exists, we don't need to actually do anything
+ break;
+ default:
+ LL_WARNS("Messaging") << "inventory_offer_callback: unknown offer type" << LL_ENDL;
+ break;
+ }
+ break;
+ // end switch (mIM)
+
+ case IOR_ACCEPT:
+ //don't spam them if they are getting flooded
+ if (check_offer_throttle(mFromName, true))
+ {
+ log_message = chatHistory_string + " " + LLTrans::getString("InvOfferGaveYou") + " " + mDesc + LLTrans::getString(".");
+ LLSD args;
+ args["MESSAGE"] = log_message;
+ LLNotificationsUtil::add("SystemMessage", args);
+ }
+ break;
+
+ case IOR_BUSY:
+ //Busy falls through to decline. Says to make busy message.
+ busy=TRUE;
+ case IOR_MUTE:
+ // MUTE falls through to decline
+ case IOR_DECLINE:
+ {
+ {
+ LLStringUtil::format_map_t log_message_args;
+ log_message_args["DESC"] = mDesc;
+ log_message_args["NAME"] = mFromName;
+ log_message = LLTrans::getString("InvOfferDecline", log_message_args);
+ }
+ chat.mText = log_message;
+ if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::getInstance()->isLinden(mFromName) ) // muting for SL-42269
+ {
+ chat.mMuted = TRUE;
+ }
+
+ // *NOTE dzaporozhan
+ // Disabled logging to old chat floater to fix crash in group notices - EXT-4149
+ // LLFloaterChat::addChatHistory(chat);
+
+ LLDiscardAgentOffer* discard_agent_offer = new LLDiscardAgentOffer(mFolderID, mObjectID);
+ discard_agent_offer->startFetch();
+ if (catp || (itemp && itemp->isFinished()))
+ {
+ discard_agent_offer->done();
+ }
+ else
+ {
+ opener = discard_agent_offer;
+ }
+
+
+ if (busy && (!mFromGroup && !mFromObject))
+ {
+ busy_message(gMessageSystem, mFromID);
+ }
+ break;
+ }
+ default:
+ // close button probably
+ // The item has already been fetched and is in your inventory, we simply won't highlight it
+ // OR delete it if the notification gets killed, since we don't want that to be a vector for
+ // losing inventory offers.
+ break;
+ }
+
+ if(opener)
+ {
+ gInventory.addObserver(opener);
+ }
+
+ if(!mPersist)
+ {
+ delete this;
+ }
+ return false;
+}
+
+bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const LLSD& response)
+{
+ LLChat chat;
+ std::string log_message;
+ S32 button = LLNotification::getSelectedOption(notification, response);
+
+ // For muting, we need to add the mute, then decline the offer.
+ // This must be done here because:
+ // * callback may be called immediately,
+ // * adding the mute sends a message,
+ // * we can't build two messages at once.
+ if (2 == button)
+ {
+ LLNotificationPtr notification_ptr = LLNotifications::instance().find(notification["id"].asUUID());
+
+ llassert(notification_ptr != NULL);
+ if (notification_ptr != NULL)
+ {
+ gCacheName->get(mFromID, mFromGroup, boost::bind(&inventory_offer_mute_callback,_1,_2,_3,notification_ptr->getResponderPtr()));
+ }
+ }
+
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_ImprovedInstantMessage);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_MessageBlock);
+ msg->addBOOLFast(_PREHASH_FromGroup, FALSE);
+ msg->addUUIDFast(_PREHASH_ToAgentID, mFromID);
+ msg->addU8Fast(_PREHASH_Offline, IM_ONLINE);
+ msg->addUUIDFast(_PREHASH_ID, mTransactionID);
+ msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary
+ std::string name;
+ LLAgentUI::buildFullname(name);
+ msg->addStringFast(_PREHASH_FromAgentName, name);
+ msg->addStringFast(_PREHASH_Message, "");
+ msg->addU32Fast(_PREHASH_ParentEstateID, 0);
+ msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null);
+ msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent());
+ LLInventoryObserver* opener = NULL;
+
+ std::string from_string; // Used in the pop-up.
+ std::string chatHistory_string; // Used in chat history.
+ if (mFromObject == TRUE)
+ {
+ if (mFromGroup)
+ {
+ std::string group_name;
+ if (gCacheName->getGroupName(mFromID, group_name))
+ {
+ from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+"'"
+ + mFromName + LLTrans::getString("'") +" " + LLTrans::getString("InvOfferOwnedByGroup")
+ + " "+ "'" + group_name + "'";
+
+ chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByGroup")
+ + " " + group_name + "'";
+ }
+ else
+ {
+ from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+"'"
+ + mFromName +"'"+ " " + LLTrans::getString("InvOfferOwnedByUnknownGroup");
+ chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownGroup");
+ }
+ }
+ else
+ {
+ std::string full_name;
+ if (gCacheName->getFullName(mFromID, full_name))
+ {
+ from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+ LLTrans::getString("'") + mFromName
+ + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + full_name;
+ chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + full_name;
+ }
+ else
+ {
+ from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+LLTrans::getString("'")
+ + mFromName + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedByUnknownUser");
+ chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownUser");
+ }
+ }
+ }
+ else
+ {
+ from_string = chatHistory_string = mFromName;
+ }
+
+ bool busy=FALSE;
+
+ switch(button)
+ {
+ case IOR_ACCEPT:
+ // ACCEPT. The math for the dialog works, because the accept
+ // for inventory_offered, task_inventory_offer or
+ // group_notice_inventory is 1 greater than the offer integer value.
+ // Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED,
+ // or IM_GROUP_NOTICE_INVENTORY_ACCEPTED
+ msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1));
+ msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(mFolderID.mData),
+ sizeof(mFolderID.mData));
+ // send the message
+ msg->sendReliable(mHost);
+
+ //don't spam them if they are getting flooded
+ if (check_offer_throttle(mFromName, true))
+ {
+ log_message = chatHistory_string + " " + LLTrans::getString("InvOfferGaveYou") + " " + mDesc + LLTrans::getString(".");
+ LLSD args;
+ args["MESSAGE"] = log_message;
+ LLNotificationsUtil::add("SystemMessage", args);
+ }
+
+ // we will want to open this item when it comes back.
+ LL_DEBUGS("Messaging") << "Initializing an opener for tid: " << mTransactionID
+ << LL_ENDL;
+ switch (mIM)
+ {
+ case IM_TASK_INVENTORY_OFFERED:
+ case IM_GROUP_NOTICE:
+ case IM_GROUP_NOTICE_REQUESTED:
+ {
+ // This is an offer from a task or group.
+ // We don't use a new instance of an opener
+ // We instead use the singular observer gOpenTaskOffer
+ // Since it already exists, we don't need to actually do anything
+ }
+ break;
+ default:
+ LL_WARNS("Messaging") << "inventory_offer_callback: unknown offer type" << LL_ENDL;
+ break;
+ } // end switch (mIM)
+ break;
+
+ case IOR_BUSY:
+ //Busy falls through to decline. Says to make busy message.
+ busy=TRUE;
+ case IOR_MUTE:
+ // MUTE falls through to decline
+ case IOR_DECLINE:
+ // DECLINE. The math for the dialog works, because the decline
+ // for inventory_offered, task_inventory_offer or
+ // group_notice_inventory is 2 greater than the offer integer value.
+ // Generates IM_INVENTORY_DECLINED, IM_TASK_INVENTORY_DECLINED,
+ // or IM_GROUP_NOTICE_INVENTORY_DECLINED
+ default:
+ // close button probably (or any of the fall-throughs from above)
+ msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 2));
+ msg->addBinaryDataFast(_PREHASH_BinaryBucket, EMPTY_BINARY_BUCKET, EMPTY_BINARY_BUCKET_SIZE);
+ // send the message
+ msg->sendReliable(mHost);
+
+ if (gSavedSettings.getBOOL("LogInventoryDecline"))
+ {
+ LLStringUtil::format_map_t log_message_args;
+ log_message_args["DESC"] = mDesc;
+ log_message_args["NAME"] = mFromName;
+ log_message = LLTrans::getString("InvOfferDecline", log_message_args);
+
+ LLSD args;
+ args["MESSAGE"] = log_message;
+ LLNotificationsUtil::add("SystemMessage", args);
+ }
+
+ if (busy && (!mFromGroup && !mFromObject))
+ {
+ busy_message(msg,mFromID);
+ }
+ break;
+ }
+
+ if(opener)
+ {
+ gInventory.addObserver(opener);
+ }
+
+ if(!mPersist)
+ {
+ delete this;
+ }
+ return false;
+}
+
+class LLPostponedOfferNotification: public LLPostponedNotification
+{
+protected:
+ /* virtual */
+ void modifyNotificationParams()
+ {
+ LLSD substitutions = mParams.substitutions;
+ substitutions["NAME"] = mName;
+ mParams.substitutions = substitutions;
+ }
+};
+
+void LLOfferInfo::initRespondFunctionMap()
+{
+ if(mRespondFunctions.empty())
+ {
+ mRespondFunctions["ObjectGiveItem"] = boost::bind(&LLOfferInfo::inventory_task_offer_callback, this, _1, _2);
+ mRespondFunctions["UserGiveItem"] = boost::bind(&LLOfferInfo::inventory_offer_callback, this, _1, _2);
+ }
+}
+
+void inventory_offer_handler(LLOfferInfo* info)
+{
+ //Until throttling is implmented, busy mode should reject inventory instead of silently
+ //accepting it. SEE SL-39554
+ if (gAgent.getBusy())
+ {
+ info->forceResponse(IOR_BUSY);
+ return;
+ }
+
+ //If muted, don't even go through the messaging stuff. Just curtail the offer here.
+ if (LLMuteList::getInstance()->isMuted(info->mFromID, info->mFromName))
+ {
+ info->forceResponse(IOR_MUTE);
+ return;
+ }
+
+ // Avoid the Accept/Discard dialog if the user so desires. JC
+ if (gSavedSettings.getBOOL("AutoAcceptNewInventory")
+ && (info->mType == LLAssetType::AT_NOTECARD
+ || info->mType == LLAssetType::AT_LANDMARK
+ || info->mType == LLAssetType::AT_TEXTURE))
+ {
+ // For certain types, just accept the items into the inventory,
+ // and possibly open them on receipt depending upon "ShowNewInventory".
+ info->forceResponse(IOR_ACCEPT);
+ return;
+ }
+
+ // Strip any SLURL from the message display. (DEV-2754)
+ std::string msg = info->mDesc;
+ int indx = msg.find(" ( http://slurl.com/secondlife/");
+ if(indx == std::string::npos)
+ {
+ // try to find new slurl host
+ indx = msg.find(" ( http://maps.secondlife.com/secondlife/");
+ }
+ if(indx >= 0)
+ {
+ LLStringUtil::truncate(msg, indx);
+ }
+
+ LLSD args;
+ args["[OBJECTNAME]"] = msg;
+
+ LLSD payload;
+
+ // must protect against a NULL return from lookupHumanReadable()
+ std::string typestr = ll_safe_string(LLAssetType::lookupHumanReadable(info->mType));
+ if (!typestr.empty())
+ {
+ // human readable matches string name from strings.xml
+ // lets get asset type localized name
+ args["OBJECTTYPE"] = LLTrans::getString(typestr);
+ }
+ else
+ {
+ LL_WARNS("Messaging") << "LLAssetType::lookupHumanReadable() returned NULL - probably bad asset type: " << info->mType << LL_ENDL;
+ args["OBJECTTYPE"] = "";
+
+ // This seems safest, rather than propagating bogosity
+ LL_WARNS("Messaging") << "Forcing an inventory-decline for probably-bad asset type." << LL_ENDL;
+ info->forceResponse(IOR_DECLINE);
+ return;
+ }
+
+ // If mObjectID is null then generate the object_id based on msg to prevent
+ // multiple creation of chiclets for same object.
+ LLUUID object_id = info->mObjectID;
+ if (object_id.isNull())
+ object_id.generate(msg);
+
+ payload["from_id"] = info->mFromID;
+ // Needed by LLScriptFloaterManager to bind original notification with
+ // faked for toast one.
+ payload["object_id"] = object_id;
+ // Flag indicating that this notification is faked for toast.
+ payload["give_inventory_notification"] = FALSE;
+ args["OBJECTFROMNAME"] = info->mFromName;
+ args["NAME"] = info->mFromName;
+ if (info->mFromGroup)
+ {
+ args["NAME_SLURL"] = LLSLURL("group", info->mFromID, "about").getSLURLString();
+ }
+ else
+ {
+ args["NAME_SLURL"] = LLSLURL("agent", info->mFromID, "about").getSLURLString();
+ }
+ std::string verb = "select?name=" + LLURI::escape(msg);
+ args["ITEM_SLURL"] = LLSLURL("inventory", info->mObjectID, verb.c_str()).getSLURLString();
+
+ LLNotification::Params p("ObjectGiveItem");
+
+ // Object -> Agent Inventory Offer
+ if (info->mFromObject)
+ {
+ // Inventory Slurls don't currently work for non agent transfers, so only display the object name.
+ args["ITEM_SLURL"] = msg;
+ // Note: sets inventory_task_offer_callback as the callback
+ p.substitutions(args).payload(payload).functor.responder(LLNotificationResponderPtr(info));
+ info->mPersist = true;
+ p.name = "ObjectGiveItem";
+ // Pop up inv offer chiclet and let the user accept (keep), or reject (and silently delete) the inventory.
+ LLPostponedNotification::add<LLPostponedOfferNotification>(p, info->mFromID, info->mFromGroup == TRUE);
+ }
+ else // Agent -> Agent Inventory Offer
+ {
+ p.responder = info;
+ // Note: sets inventory_offer_callback as the callback
+ // *TODO fix memory leak
+ // inventory_offer_callback() is not invoked if user received notification and
+ // closes viewer(without responding the notification)
+ p.substitutions(args).payload(payload).functor.responder(LLNotificationResponderPtr(info));
+ info->mPersist = true;
+ p.name = "UserGiveItem";
+
+ // Prefetch the item into your local inventory.
+ LLInventoryFetchItemsObserver* fetch_item = new LLInventoryFetchItemsObserver(info->mObjectID);
+ fetch_item->startFetch();
+ if(fetch_item->isFinished())
+ {
+ fetch_item->done();
+ }
+ else
+ {
+ gInventory.addObserver(fetch_item);
+ }
+
+ // In viewer 2 we're now auto receiving inventory offers and messaging as such (not sending reject messages).
+ info->send_auto_receive_response();
+
+ // Inform user that there is a script floater via toast system
+ {
+ payload["give_inventory_notification"] = TRUE;
+ p.payload = payload;
+ LLPostponedNotification::add<LLPostponedOfferNotification>(p, info->mFromID, false);
+ }
+ }
+
+ LLFirstUse::newInventory();
+}
+
+bool lure_callback(const LLSD& notification, const LLSD& response)
+{
+ S32 option = 0;
+ if (response.isInteger())
+ {
+ option = response.asInteger();
+ }
+ else
+ {
+ option = LLNotificationsUtil::getSelectedOption(notification, response);
+ }
+
+ LLUUID from_id = notification["payload"]["from_id"].asUUID();
+ LLUUID lure_id = notification["payload"]["lure_id"].asUUID();
+ BOOL godlike = notification["payload"]["godlike"].asBoolean();
+
+ switch(option)
+ {
+ case 0:
+ {
+ // accept
+ gAgent.teleportViaLure(lure_id, godlike);
+ }
+ break;
+ case 1:
+ default:
+ // decline
+ send_simple_im(from_id,
+ LLStringUtil::null,
+ IM_LURE_DECLINED,
+ lure_id);
+ break;
+ }
+ return false;
+}
+static LLNotificationFunctorRegistration lure_callback_reg("TeleportOffered", lure_callback);
+
+bool goto_url_callback(const LLSD& notification, const LLSD& response)
+{
+ std::string url = notification["payload"]["url"].asString();
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if(1 == option)
+ {
+ LLWeb::loadURL(url);
+ }
+ return false;
+}
+static LLNotificationFunctorRegistration goto_url_callback_reg("GotoURL", goto_url_callback);
+
+bool inspect_remote_object_callback(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (0 == option)
+ {
+ LLFloaterReg::showInstance("inspect_remote_object", notification["payload"]);
+ }
+ return false;
+}
+static LLNotificationFunctorRegistration inspect_remote_object_callback_reg("ServerObjectMessage", inspect_remote_object_callback);
+
+class LLPostponedServerObjectNotification: public LLPostponedNotification
+{
+protected:
+ /* virtual */
+ void modifyNotificationParams()
+ {
+ LLSD payload = mParams.payload;
+ mParams.payload = payload;
+ }
+};
+
+static bool parse_lure_bucket(const std::string& bucket,
+ U64& region_handle,
+ LLVector3& pos,
+ LLVector3& look_at,
+ U8& region_access)
+{
+ // tokenize the bucket
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ boost::char_separator<char> sep("|", "", boost::keep_empty_tokens);
+ tokenizer tokens(bucket, sep);
+ tokenizer::iterator iter = tokens.begin();
+
+ S32 gx,gy,rx,ry,rz,lx,ly,lz;
+ try
+ {
+ gx = boost::lexical_cast<S32>((*(iter)).c_str());
+ gy = boost::lexical_cast<S32>((*(++iter)).c_str());
+ rx = boost::lexical_cast<S32>((*(++iter)).c_str());
+ ry = boost::lexical_cast<S32>((*(++iter)).c_str());
+ rz = boost::lexical_cast<S32>((*(++iter)).c_str());
+ lx = boost::lexical_cast<S32>((*(++iter)).c_str());
+ ly = boost::lexical_cast<S32>((*(++iter)).c_str());
+ lz = boost::lexical_cast<S32>((*(++iter)).c_str());
+ }
+ catch( boost::bad_lexical_cast& )
+ {
+ LL_WARNS("parse_lure_bucket")
+ << "Couldn't parse lure bucket."
+ << LL_ENDL;
+ return false;
+ }
+ // Grab region access
+ region_access = SIM_ACCESS_MIN;
+ if (++iter != tokens.end())
+ {
+ std::string access_str((*iter).c_str());
+ LLStringUtil::trim(access_str);
+ if ( access_str == "A" )
+ {
+ region_access = SIM_ACCESS_ADULT;
+ }
+ else if ( access_str == "M" )
+ {
+ region_access = SIM_ACCESS_MATURE;
+ }
+ else if ( access_str == "PG" )
+ {
+ region_access = SIM_ACCESS_PG;
+ }
+ }
+
+ pos.setVec((F32)rx, (F32)ry, (F32)rz);
+ look_at.setVec((F32)lx, (F32)ly, (F32)lz);
+
+ region_handle = to_region_handle(gx, gy);
+ return true;
+}
+
+// Strip out "Resident" for display, but only if the message came from a user
+// (rather than a script)
+static std::string clean_name_from_im(const std::string& name, EInstantMessage type)
+{
+ switch(type)
+ {
+ case IM_NOTHING_SPECIAL:
+ case IM_MESSAGEBOX:
+ case IM_GROUP_INVITATION:
+ case IM_INVENTORY_OFFERED:
+ case IM_INVENTORY_ACCEPTED:
+ case IM_INVENTORY_DECLINED:
+ case IM_GROUP_VOTE:
+ case IM_GROUP_MESSAGE_DEPRECATED:
+ //IM_TASK_INVENTORY_OFFERED
+ //IM_TASK_INVENTORY_ACCEPTED
+ //IM_TASK_INVENTORY_DECLINED
+ case IM_NEW_USER_DEFAULT:
+ case IM_SESSION_INVITE:
+ case IM_SESSION_P2P_INVITE:
+ case IM_SESSION_GROUP_START:
+ case IM_SESSION_CONFERENCE_START:
+ case IM_SESSION_SEND:
+ case IM_SESSION_LEAVE:
+ //IM_FROM_TASK
+ case IM_BUSY_AUTO_RESPONSE:
+ case IM_CONSOLE_AND_CHAT_HISTORY:
+ case IM_LURE_USER:
+ case IM_LURE_ACCEPTED:
+ case IM_LURE_DECLINED:
+ case IM_GODLIKE_LURE_USER:
+ case IM_YET_TO_BE_USED:
+ case IM_GROUP_ELECTION_DEPRECATED:
+ //IM_GOTO_URL
+ //IM_FROM_TASK_AS_ALERT
+ case IM_GROUP_NOTICE:
+ case IM_GROUP_NOTICE_INVENTORY_ACCEPTED:
+ case IM_GROUP_NOTICE_INVENTORY_DECLINED:
+ case IM_GROUP_INVITATION_ACCEPT:
+ case IM_GROUP_INVITATION_DECLINE:
+ case IM_GROUP_NOTICE_REQUESTED:
+ case IM_FRIENDSHIP_OFFERED:
+ case IM_FRIENDSHIP_ACCEPTED:
+ case IM_FRIENDSHIP_DECLINED_DEPRECATED:
+ //IM_TYPING_START
+ //IM_TYPING_STOP
+ return LLCacheName::cleanFullName(name);
+ default:
+ return name;
+ }
+}
+
+static std::string clean_name_from_task_im(const std::string& msg,
+ BOOL from_group)
+{
+ boost::smatch match;
+ static const boost::regex returned_exp(
+ "(.*been returned to your inventory lost and found folder by )(.+)( (from|near).*)");
+ if (boost::regex_match(msg, match, returned_exp))
+ {
+ // match objects are 1-based for groups
+ std::string final = match[1].str();
+ std::string name = match[2].str();
+ // Don't try to clean up group names
+ if (!from_group)
+ {
+ if (LLAvatarNameCache::useDisplayNames())
+ {
+ // ...just convert to username
+ final += LLCacheName::buildUsername(name);
+ }
+ else
+ {
+ // ...strip out legacy "Resident" name
+ final += LLCacheName::cleanFullName(name);
+ }
+ }
+ final += match[3].str();
+ return final;
+ }
+ return msg;
+}
+
+void notification_display_name_callback(const LLUUID& id,
+ const LLAvatarName& av_name,
+ const std::string& name,
+ LLSD& substitutions,
+ const LLSD& payload)
+{
+ substitutions["NAME"] = av_name.mDisplayName;
+ LLNotificationsUtil::add(name, substitutions, payload);
+}
+
+class LLPostponedIMSystemTipNotification: public LLPostponedNotification
+{
+protected:
+ /* virtual */
+ void modifyNotificationParams()
+ {
+ LLSD payload = mParams.payload;
+ payload["SESSION_NAME"] = mName;
+ mParams.payload = payload;
+ }
+
+};
+
+// Callback for name resolution of a god/estate message
+void god_message_name_cb(const LLAvatarName& av_name, LLChat chat, std::string message)
+{
+ LLSD args;
+ args["NAME"] = av_name.getCompleteName();
+ args["MESSAGE"] = message;
+ LLNotificationsUtil::add("GodMessage", args);
+
+ // Treat like a system message and put in chat history.
+ chat.mText = av_name.getCompleteName() + ": " + message;
+
+ LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD());
+ if(nearby_chat)
+ {
+ nearby_chat->addMessage(chat);
+ }
+
+}
+
+void process_improved_im(LLMessageSystem *msg, void **user_data)
+{
+ if (gNoRender)
+ {
+ return;
+ }
+ LLUUID from_id;
+ BOOL from_group;
+ LLUUID to_id;
+ U8 offline;
+ U8 d = 0;
+ LLUUID session_id;
+ U32 timestamp;
+ std::string name;
+ std::string message;
+ U32 parent_estate_id = 0;
+ LLUUID region_id;
+ LLVector3 position;
+ U8 binary_bucket[MTUBYTES];
+ S32 binary_bucket_size;
+ LLChat chat;
+ std::string buffer;
+
+ // *TODO: Translate - need to fix the full name to first/last (maybe)
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, from_id);
+ msg->getBOOLFast(_PREHASH_MessageBlock, _PREHASH_FromGroup, from_group);
+ msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ToAgentID, to_id);
+ msg->getU8Fast( _PREHASH_MessageBlock, _PREHASH_Offline, offline);
+ msg->getU8Fast( _PREHASH_MessageBlock, _PREHASH_Dialog, d);
+ msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ID, session_id);
+ msg->getU32Fast( _PREHASH_MessageBlock, _PREHASH_Timestamp, timestamp);
+ //msg->getData("MessageBlock", "Count", &count);
+ msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_FromAgentName, name);
+ msg->getStringFast(_PREHASH_MessageBlock, _PREHASH_Message, message);
+ msg->getU32Fast(_PREHASH_MessageBlock, _PREHASH_ParentEstateID, parent_estate_id);
+ msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_RegionID, region_id);
+ msg->getVector3Fast(_PREHASH_MessageBlock, _PREHASH_Position, position);
+ msg->getBinaryDataFast( _PREHASH_MessageBlock, _PREHASH_BinaryBucket, binary_bucket, 0, 0, MTUBYTES);
+ binary_bucket_size = msg->getSizeFast(_PREHASH_MessageBlock, _PREHASH_BinaryBucket);
+ EInstantMessage dialog = (EInstantMessage)d;
+
+ // make sure that we don't have an empty or all-whitespace name
+ LLStringUtil::trim(name);
+ if (name.empty())
+ {
+ name = LLTrans::getString("Unnamed");
+ }
+ // IDEVO convert new-style "Resident" names for display
+ name = clean_name_from_im(name, dialog);
+
+ BOOL is_busy = gAgent.getBusy();
+ BOOL is_muted = LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat);
+ BOOL is_linden = LLMuteList::getInstance()->isLinden(name);
+ BOOL is_owned_by_me = FALSE;
+ BOOL is_friend = (LLAvatarTracker::instance().getBuddyInfo(from_id) == NULL) ? false : true;
+ BOOL accept_im_from_only_friend = gSavedSettings.getBOOL("VoiceCallsFriendsOnly");
+
+ chat.mMuted = is_muted && !is_linden;
+ chat.mFromID = from_id;
+ chat.mFromName = name;
+ chat.mSourceType = (from_id.isNull() || (name == std::string(SYSTEM_FROM))) ? CHAT_SOURCE_SYSTEM : CHAT_SOURCE_AGENT;
+
+ LLViewerObject *source = gObjectList.findObject(session_id); //Session ID is probably the wrong thing.
+ if (source)
+ {
+ is_owned_by_me = source->permYouOwner();
+ }
+
+ std::string separator_string(": ");
+
+ LLSD args;
+ LLSD payload;
+ LLNotification::Params params;
+
+ switch(dialog)
+ {
+ case IM_CONSOLE_AND_CHAT_HISTORY:
+ args["MESSAGE"] = message;
+ payload["from_id"] = from_id;
+
+ params.name = "IMSystemMessageTip";
+ params.substitutions = args;
+ params.payload = payload;
+ LLPostponedNotification::add<LLPostponedIMSystemTipNotification>(params, from_id, false);
+ break;
+
+ case IM_NOTHING_SPECIAL:
+ // Don't show dialog, just do IM
+ if (!gAgent.isGodlike()
+ && gAgent.getRegion()->isPrelude()
+ && to_id.isNull() )
+ {
+ // do nothing -- don't distract newbies in
+ // Prelude with global IMs
+ }
+ else if (offline == IM_ONLINE && !is_linden && is_busy && name != SYSTEM_FROM)
+ {
+ // return a standard "busy" message, but only do it to online IM
+ // (i.e. not other auto responses and not store-and-forward IM)
+ if (!gIMMgr->hasSession(session_id))
+ {
+ // if there is not a panel for this conversation (i.e. it is a new IM conversation
+ // initiated by the other party) then...
+ std::string my_name;
+ LLAgentUI::buildFullname(my_name);
+ std::string response = gSavedPerAccountSettings.getString("BusyModeResponse");
+ pack_instant_message(
+ gMessageSystem,
+ gAgent.getID(),
+ FALSE,
+ gAgent.getSessionID(),
+ from_id,
+ my_name,
+ response,
+ IM_ONLINE,
+ IM_BUSY_AUTO_RESPONSE,
+ session_id);
+ gAgent.sendReliableMessage();
+ }
+
+ // now store incoming IM in chat history
+
+ buffer = message;
+
+ LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL;
+
+ // add to IM panel, but do not bother the user
+ gIMMgr->addMessage(
+ session_id,
+ from_id,
+ name,
+ buffer,
+ LLStringUtil::null,
+ dialog,
+ parent_estate_id,
+ region_id,
+ position,
+ true);
+ }
+ else if (from_id.isNull())
+ {
+ LLSD args;
+ args["MESSAGE"] = message;
+ LLNotificationsUtil::add("SystemMessage", args);
+ }
+ else if (to_id.isNull())
+ {
+ // Message to everyone from GOD, look up the fullname since
+ // server always slams name to legacy names
+ LLAvatarNameCache::get(from_id, boost::bind(god_message_name_cb, _2, chat, message));
+ }
+ else
+ {
+ // standard message, not from system
+ std::string saved;
+ if(offline == IM_OFFLINE)
+ {
+ LLStringUtil::format_map_t args;
+ args["[LONG_TIMESTAMP]"] = formatted_time(timestamp);
+ saved = LLTrans::getString("Saved_message", args);
+ }
+ buffer = saved + message;
+
+ LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL;
+
+ bool mute_im = is_muted;
+ if(accept_im_from_only_friend&&!is_friend)
+ {
+ mute_im = true;
+ }
+ if (!mute_im || is_linden)
+ {
+ gIMMgr->addMessage(
+ session_id,
+ from_id,
+ name,
+ buffer,
+ LLStringUtil::null,
+ dialog,
+ parent_estate_id,
+ region_id,
+ position,
+ true);
+ }
+ else
+ {
+ /*
+ EXT-5099
+ currently there is no way to store in history only...
+ using LLNotificationsUtil::add will add message to Nearby Chat
+
+ // muted user, so don't start an IM session, just record line in chat
+ // history. Pretend the chat is from a local agent,
+ // so it will go into the history but not be shown on screen.
+
+ LLSD args;
+ args["MESSAGE"] = buffer;
+ LLNotificationsUtil::add("SystemMessageTip", args);
+ */
+ }
+ }
+ break;
+
+ case IM_TYPING_START:
+ {
+ LLPointer<LLIMInfo> im_info = new LLIMInfo(gMessageSystem);
+ gIMMgr->processIMTypingStart(im_info);
+ }
+ break;
+
+ case IM_TYPING_STOP:
+ {
+ LLPointer<LLIMInfo> im_info = new LLIMInfo(gMessageSystem);
+ gIMMgr->processIMTypingStop(im_info);
+ }
+ break;
+
+ case IM_MESSAGEBOX:
+ {
+ // This is a block, modeless dialog.
+ //*TODO: Translate
+ args["MESSAGE"] = message;
+ LLNotificationsUtil::add("SystemMessageTip", args);
+ }
+ break;
+ case IM_GROUP_NOTICE:
+ case IM_GROUP_NOTICE_REQUESTED:
+ {
+ LL_INFOS("Messaging") << "Received IM_GROUP_NOTICE message." << LL_ENDL;
+ // Read the binary bucket for more information.
+ struct notice_bucket_header_t
+ {
+ U8 has_inventory;
+ U8 asset_type;
+ LLUUID group_id;
+ };
+ struct notice_bucket_full_t
+ {
+ struct notice_bucket_header_t header;
+ U8 item_name[DB_INV_ITEM_NAME_BUF_SIZE];
+ }* notice_bin_bucket;
+
+ // Make sure the binary bucket is big enough to hold the header
+ // and a null terminated item name.
+ if ( (binary_bucket_size < (S32)((sizeof(notice_bucket_header_t) + sizeof(U8))))
+ || (binary_bucket[binary_bucket_size - 1] != '\0') )
+ {
+ LL_WARNS("Messaging") << "Malformed group notice binary bucket" << LL_ENDL;
+ break;
+ }
+
+ notice_bin_bucket = (struct notice_bucket_full_t*) &binary_bucket[0];
+ U8 has_inventory = notice_bin_bucket->header.has_inventory;
+ U8 asset_type = notice_bin_bucket->header.asset_type;
+ LLUUID group_id = notice_bin_bucket->header.group_id;
+ std::string item_name = ll_safe_string((const char*) notice_bin_bucket->item_name);
+
+ // If there is inventory, give the user the inventory offer.
+ LLOfferInfo* info = NULL;
+
+ if (has_inventory)
+ {
+ info = new LLOfferInfo();
+
+ info->mIM = IM_GROUP_NOTICE;
+ info->mFromID = from_id;
+ info->mFromGroup = from_group;
+ info->mTransactionID = session_id;
+ info->mType = (LLAssetType::EType) asset_type;
+ info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType));
+ std::string from_name;
+
+ from_name += "A group member named ";
+ from_name += name;
+
+ info->mFromName = from_name;
+ info->mDesc = item_name;
+ info->mHost = msg->getSender();
+ }
+
+ std::string str(message);
+
+ // Tokenize the string.
+ // TODO: Support escaped tokens ("||" -> "|")
+ typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
+ boost::char_separator<char> sep("|","",boost::keep_empty_tokens);
+ tokenizer tokens(str, sep);
+ tokenizer::iterator iter = tokens.begin();
+
+ std::string subj(*iter++);
+ std::string mes(*iter++);
+
+ // Send the notification down the new path.
+ // For requested notices, we don't want to send the popups.
+ if (dialog != IM_GROUP_NOTICE_REQUESTED)
+ {
+ payload["subject"] = subj;
+ payload["message"] = mes;
+ payload["sender_name"] = name;
+ payload["group_id"] = group_id;
+ payload["inventory_name"] = item_name;
+ payload["inventory_offer"] = info ? info->asLLSD() : LLSD();
+
+ LLSD args;
+ args["SUBJECT"] = subj;
+ args["MESSAGE"] = mes;
+ LLNotifications::instance().add(LLNotification::Params("GroupNotice").substitutions(args).payload(payload).time_stamp(timestamp));
+ }
+
+ // Also send down the old path for now.
+ if (IM_GROUP_NOTICE_REQUESTED == dialog)
+ {
+
+ LLPanelGroup::showNotice(subj,mes,group_id,has_inventory,item_name,info);
+ }
+ else
+ {
+ delete info;
+ }
+ }
+ break;
+ case IM_GROUP_INVITATION:
+ {
+ //if (!is_linden && (is_busy || is_muted))
+ if ((is_busy || is_muted))
+ {
+ LLMessageSystem *msg = gMessageSystem;
+ busy_message(msg,from_id);
+ }
+ else
+ {
+ LL_INFOS("Messaging") << "Received IM_GROUP_INVITATION message." << LL_ENDL;
+ // Read the binary bucket for more information.
+ struct invite_bucket_t
+ {
+ S32 membership_fee;
+ LLUUID role_id;
+ }* invite_bucket;
+
+ // Make sure the binary bucket is the correct size.
+ if (binary_bucket_size != sizeof(invite_bucket_t))
+ {
+ LL_WARNS("Messaging") << "Malformed group invite binary bucket" << LL_ENDL;
+ break;
+ }
+
+ invite_bucket = (struct invite_bucket_t*) &binary_bucket[0];
+ S32 membership_fee = ntohl(invite_bucket->membership_fee);
+
+ LLSD payload;
+ payload["transaction_id"] = session_id;
+ payload["group_id"] = from_id;
+ payload["name"] = name;
+ payload["message"] = message;
+ payload["fee"] = membership_fee;
+
+ LLSD args;
+ args["MESSAGE"] = message;
+ // we shouldn't pass callback functor since it is registered in LLFunctorRegistration
+ LLNotificationsUtil::add("JoinGroup", args, payload);
+ }
+ }
+ break;
+
+ case IM_INVENTORY_OFFERED:
+ case IM_TASK_INVENTORY_OFFERED:
+ // Someone has offered us some inventory.
+ {
+ LLOfferInfo* info = new LLOfferInfo;
+ if (IM_INVENTORY_OFFERED == dialog)
+ {
+ struct offer_agent_bucket_t
+ {
+ S8 asset_type;
+ LLUUID object_id;
+ }* bucketp;
+
+ if (sizeof(offer_agent_bucket_t) != binary_bucket_size)
+ {
+ LL_WARNS("Messaging") << "Malformed inventory offer from agent" << LL_ENDL;
+ delete info;
+ break;
+ }
+ bucketp = (struct offer_agent_bucket_t*) &binary_bucket[0];
+ info->mType = (LLAssetType::EType) bucketp->asset_type;
+ info->mObjectID = bucketp->object_id;
+ }
+ else
+ {
+ if (sizeof(S8) != binary_bucket_size)
+ {
+ LL_WARNS("Messaging") << "Malformed inventory offer from object" << LL_ENDL;
+ delete info;
+ break;
+ }
+ info->mType = (LLAssetType::EType) binary_bucket[0];
+ info->mObjectID = LLUUID::null;
+ }
+
+ info->mIM = dialog;
+ info->mFromID = from_id;
+ info->mFromGroup = from_group;
+ info->mTransactionID = session_id;
+ info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType));
+
+ if (dialog == IM_TASK_INVENTORY_OFFERED)
+ {
+ info->mFromObject = TRUE;
+ }
+ else
+ {
+ info->mFromObject = FALSE;
+ }
+ info->mFromName = name;
+ info->mDesc = message;
+ info->mHost = msg->getSender();
+ //if (((is_busy && !is_owned_by_me) || is_muted))
+ if (is_muted)
+ {
+ // Prefetch the offered item so that it can be discarded by the appropriate observer. (EXT-4331)
+ LLInventoryFetchItemsObserver* fetch_item = new LLInventoryFetchItemsObserver(info->mObjectID);
+ fetch_item->startFetch();
+ delete fetch_item;
+
+ // Same as closing window
+ info->forceResponse(IOR_DECLINE);
+ }
+ else
+ {
+ inventory_offer_handler(info);
+ }
+ }
+ break;
+
+ case IM_INVENTORY_ACCEPTED:
+ {
+ args["NAME"] = LLSLURL("agent", from_id, "completename").getSLURLString();;
+ LLSD payload;
+ payload["from_id"] = from_id;
+ LLNotificationsUtil::add("InventoryAccepted", args, payload);
+ break;
+ }
+ case IM_INVENTORY_DECLINED:
+ {
+ args["NAME"] = LLSLURL("agent", from_id, "completename").getSLURLString();;
+ LLSD payload;
+ payload["from_id"] = from_id;
+ LLNotificationsUtil::add("InventoryDeclined", args, payload);
+ break;
+ }
+ // TODO: _DEPRECATED suffix as part of vote removal - DEV-24856
+ case IM_GROUP_VOTE:
+ {
+ LL_WARNS("Messaging") << "Received IM: IM_GROUP_VOTE_DEPRECATED" << LL_ENDL;
+ }
+ break;
+
+ case IM_GROUP_ELECTION_DEPRECATED:
+ {
+ LL_WARNS("Messaging") << "Received IM: IM_GROUP_ELECTION_DEPRECATED" << LL_ENDL;
+ }
+ break;
+
+ case IM_SESSION_SEND:
+ {
+ if (!is_linden && is_busy)
+ {
+ return;
+ }
+
+ // Only show messages if we have a session open (which
+ // should happen after you get an "invitation"
+ if ( !gIMMgr->hasSession(session_id) )
+ {
+ return;
+ }
+
+ // standard message, not from system
+ std::string saved;
+ if(offline == IM_OFFLINE)
+ {
+ saved = llformat("(Saved %s) ", formatted_time(timestamp).c_str());
+ }
+ buffer = saved + message;
+ BOOL is_this_agent = FALSE;
+ if(from_id == gAgentID)
+ {
+ is_this_agent = TRUE;
+ }
+ gIMMgr->addMessage(
+ session_id,
+ from_id,
+ name,
+ buffer,
+ ll_safe_string((char*)binary_bucket),
+ IM_SESSION_INVITE,
+ parent_estate_id,
+ region_id,
+ position,
+ true);
+ }
+ break;
+
+ case IM_FROM_TASK:
+ {
+ if (is_busy && !is_owned_by_me)
+ {
+ return;
+ }
+
+ // Build a link to open the object IM info window.
+ std::string location = ll_safe_string((char*)binary_bucket, binary_bucket_size-1);
+
+ if (session_id.notNull())
+ {
+ chat.mFromID = session_id;
+ }
+ else
+ {
+ // This message originated on a region without the updated code for task id and slurl information.
+ // We just need a unique ID for this object that isn't the owner ID.
+ // If it is the owner ID it will overwrite the style that contains the link to that owner's profile.
+ // This isn't ideal - it will make 1 style for all objects owned by the the same person/group.
+ // This works because the only thing we can really do in this case is show the owner name and link to their profile.
+ chat.mFromID = from_id ^ gAgent.getSessionID();
+ }
+
+ chat.mSourceType = CHAT_SOURCE_OBJECT;
+
+ if(SYSTEM_FROM == name)
+ {
+ // System's UUID is NULL (fixes EXT-4766)
+ chat.mFromID = LLUUID::null;
+ chat.mSourceType = CHAT_SOURCE_SYSTEM;
+ }
+
+ // IDEVO Some messages have embedded resident names
+ message = clean_name_from_task_im(message, from_group);
+
+ LLSD query_string;
+ query_string["owner"] = from_id;
+ query_string["slurl"] = location;
+ query_string["name"] = name;
+ if (from_group)
+ {
+ query_string["groupowned"] = "true";
+ }
+
+ chat.mURL = LLSLURL("objectim", session_id, "").getSLURLString();
+ chat.mText = message;
+
+ // Note: lie to Nearby Chat, pretending that this is NOT an IM, because
+ // IMs from obejcts don't open IM sessions.
+ LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD());
+ if(SYSTEM_FROM != name && nearby_chat)
+ {
+ chat.mOwnerID = from_id;
+ LLSD args;
+ args["slurl"] = location;
+ args["type"] = LLNotificationsUI::NT_NEARBYCHAT;
+
+ // Look for IRC-style emotes here so object name formatting is correct
+ std::string prefix = message.substr(0, 4);
+ if (prefix == "/me " || prefix == "/me'")
+ {
+ chat.mChatStyle = CHAT_STYLE_IRC;
+ }
+
+ LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args);
+ }
+
+
+ //Object IMs send with from name: 'Second Life' need to be displayed also in notification toasts (EXT-1590)
+ if (SYSTEM_FROM != name) break;
+
+ LLSD substitutions;
+ substitutions["NAME"] = name;
+ substitutions["MSG"] = message;
+
+ LLSD payload;
+ payload["object_id"] = session_id;
+ payload["owner_id"] = from_id;
+ payload["from_id"] = from_id;
+ payload["slurl"] = location;
+ payload["name"] = name;
+ std::string session_name;
+ if (from_group)
+ {
+ payload["group_owned"] = "true";
+ }
+
+ LLNotification::Params params("ServerObjectMessage");
+ params.substitutions = substitutions;
+ params.payload = payload;
+
+ LLPostponedNotification::add<LLPostponedServerObjectNotification>(params, from_id, from_group);
+ }
+ break;
+ case IM_FROM_TASK_AS_ALERT:
+ if (is_busy && !is_owned_by_me)
+ {
+ return;
+ }
+ {
+ // Construct a viewer alert for this message.
+ args["NAME"] = name;
+ args["MESSAGE"] = message;
+ LLNotificationsUtil::add("ObjectMessage", args);
+ }
+ break;
+ case IM_BUSY_AUTO_RESPONSE:
+ if (is_muted)
+ {
+ LL_DEBUGS("Messaging") << "Ignoring busy response from " << from_id << LL_ENDL;
+ return;
+ }
+ else
+ {
+ // TODO: after LLTrans hits release, get "busy response" into translatable file
+ buffer = llformat("%s (%s): %s", name.c_str(), "busy response", message.c_str());
+ gIMMgr->addMessage(session_id, from_id, name, buffer);
+ }
+ break;
+
+ case IM_LURE_USER:
+ {
+ if (is_muted)
+ {
+ return;
+ }
+ else if (is_busy)
+ {
+ busy_message(msg,from_id);
+ }
+ else
+ {
+ LLVector3 pos, look_at;
+ U64 region_handle;
+ U8 region_access = SIM_ACCESS_MIN;
+ std::string region_info = ll_safe_string((char*)binary_bucket, binary_bucket_size);
+ std::string region_access_str = LLStringUtil::null;
+ std::string region_access_icn = LLStringUtil::null;
+
+ if (parse_lure_bucket(region_info, region_handle, pos, look_at, region_access))
+ {
+ region_access_str = LLViewerRegion::accessToString(region_access);
+ region_access_icn = LLViewerRegion::getAccessIcon(region_access);
+ }
+
+ LLSD args;
+ // *TODO: Translate -> [FIRST] [LAST] (maybe)
+ args["NAME_SLURL"] = LLSLURL("agent", from_id, "about").getSLURLString();
+ args["MESSAGE"] = message;
+ args["MATURITY_STR"] = region_access_str;
+ args["MATURITY_ICON"] = region_access_icn;
+ LLSD payload;
+ payload["from_id"] = from_id;
+ payload["lure_id"] = session_id;
+ payload["godlike"] = FALSE;
+
+ LLNotification::Params params("TeleportOffered");
+ params.substitutions = args;
+ params.payload = payload;
+ LLPostponedNotification::add<LLPostponedOfferNotification>( params, from_id, false);
+ }
+ }
+ break;
+
+ case IM_GODLIKE_LURE_USER:
+ {
+ LLSD payload;
+ payload["from_id"] = from_id;
+ payload["lure_id"] = session_id;
+ payload["godlike"] = TRUE;
+ // do not show a message box, because you're about to be
+ // teleported.
+ LLNotifications::instance().forceResponse(LLNotification::Params("TeleportOffered").payload(payload), 0);
+ }
+ break;
+
+ case IM_GOTO_URL:
+ {
+ LLSD args;
+ // n.b. this is for URLs sent by the system, not for
+ // URLs sent by scripts (i.e. llLoadURL)
+ if (binary_bucket_size <= 0)
+ {
+ LL_WARNS("Messaging") << "bad binary_bucket_size: "
+ << binary_bucket_size
+ << " - aborting function." << LL_ENDL;
+ return;
+ }
+
+ std::string url;
+
+ url.assign((char*)binary_bucket, binary_bucket_size-1);
+ args["MESSAGE"] = message;
+ args["URL"] = url;
+ LLSD payload;
+ payload["url"] = url;
+ LLNotificationsUtil::add("GotoURL", args, payload );
+ }
+ break;
+
+ case IM_FRIENDSHIP_OFFERED:
+ {
+ LLSD payload;
+ payload["from_id"] = from_id;
+ payload["session_id"] = session_id;;
+ payload["online"] = (offline == IM_ONLINE);
+ payload["sender"] = msg->getSender().getIPandPort();
+
+ if (is_busy)
+ {
+ busy_message(msg, from_id);
+ LLNotifications::instance().forceResponse(LLNotification::Params("OfferFriendship").payload(payload), 1);
+ }
+ else if (is_muted)
+ {
+ LLNotifications::instance().forceResponse(LLNotification::Params("OfferFriendship").payload(payload), 1);
+ }
+ else
+ {
+ args["NAME_SLURL"] = LLSLURL("agent", from_id, "about").getSLURLString();
+ if(message.empty())
+ {
+ //support for frienship offers from clients before July 2008
+ LLNotificationsUtil::add("OfferFriendshipNoMessage", args, payload);
+ }
+ else
+ {
+ args["[MESSAGE]"] = message;
+ LLNotification::Params params("OfferFriendship");
+ params.substitutions = args;
+ params.payload = payload;
+ LLPostponedNotification::add<LLPostponedOfferNotification>( params, from_id, false);
+ }
+ }
+ }
+ break;
+
+ case IM_FRIENDSHIP_ACCEPTED:
+ {
+ // In the case of an offline IM, the formFriendship() may be extraneous
+ // as the database should already include the relationship. But it
+ // doesn't hurt for dupes.
+ LLAvatarTracker::formFriendship(from_id);
+
+ std::vector<std::string> strings;
+ strings.push_back(from_id.asString());
+ send_generic_message("requestonlinenotification", strings);
+
+ args["NAME"] = name;
+ LLSD payload;
+ payload["from_id"] = from_id;
+ LLAvatarNameCache::get(from_id, boost::bind(¬ification_display_name_callback,
+ _1,
+ _2,
+ "FriendshipAccepted",
+ args,
+ payload));
+ }
+ break;
+
+ case IM_FRIENDSHIP_DECLINED_DEPRECATED:
+ default:
+ LL_WARNS("Messaging") << "Instant message calling for unknown dialog "
+ << (S32)dialog << LL_ENDL;
+ break;
+ }
+
+ LLWindow* viewer_window = gViewerWindow->getWindow();
+ if (viewer_window && viewer_window->getMinimized())
+ {
+ viewer_window->flashIcon(5.f);
+ }
+}
+
+void busy_message (LLMessageSystem* msg, LLUUID from_id)
+{
+ if (gAgent.getBusy())
+ {
+ std::string my_name;
+ LLAgentUI::buildFullname(my_name);
+ std::string response = gSavedPerAccountSettings.getString("BusyModeResponse");
+ pack_instant_message(
+ gMessageSystem,
+ gAgent.getID(),
+ FALSE,
+ gAgent.getSessionID(),
+ from_id,
+ my_name,
+ response,
+ IM_ONLINE,
+ IM_BUSY_AUTO_RESPONSE);
+ gAgent.sendReliableMessage();
+ }
+}
+
+bool callingcard_offer_callback(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ LLUUID fid;
+ LLUUID from_id;
+ LLMessageSystem* msg = gMessageSystem;
+ switch(option)
+ {
+ case 0:
+ // accept
+ msg->newMessageFast(_PREHASH_AcceptCallingCard);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_TransactionBlock);
+ msg->addUUIDFast(_PREHASH_TransactionID, notification["payload"]["transaction_id"].asUUID());
+ fid = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD);
+ msg->nextBlockFast(_PREHASH_FolderData);
+ msg->addUUIDFast(_PREHASH_FolderID, fid);
+ msg->sendReliable(LLHost(notification["payload"]["sender"].asString()));
+ break;
+ case 1:
+ // decline
+ msg->newMessageFast(_PREHASH_DeclineCallingCard);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_TransactionBlock);
+ msg->addUUIDFast(_PREHASH_TransactionID, notification["payload"]["transaction_id"].asUUID());
+ msg->sendReliable(LLHost(notification["payload"]["sender"].asString()));
+ busy_message(msg, notification["payload"]["source_id"].asUUID());
+ break;
+ default:
+ // close button probably, possibly timed out
+ break;
+ }
+
+ return false;
+}
+static LLNotificationFunctorRegistration callingcard_offer_cb_reg("OfferCallingCard", callingcard_offer_callback);
+
+void process_offer_callingcard(LLMessageSystem* msg, void**)
+{
+ // someone has offered to form a friendship
+ LL_DEBUGS("Messaging") << "callingcard offer" << LL_ENDL;
+
+ LLUUID source_id;
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, source_id);
+ LLUUID tid;
+ msg->getUUIDFast(_PREHASH_AgentBlock, _PREHASH_TransactionID, tid);
+
+ LLSD payload;
+ payload["transaction_id"] = tid;
+ payload["source_id"] = source_id;
+ payload["sender"] = msg->getSender().getIPandPort();
+
+ LLViewerObject* source = gObjectList.findObject(source_id);
+ LLSD args;
+ std::string source_name;
+ if(source && source->isAvatar())
+ {
+ LLNameValue* nvfirst = source->getNVPair("FirstName");
+ LLNameValue* nvlast = source->getNVPair("LastName");
+ if (nvfirst && nvlast)
+ {
+ source_name = LLCacheName::buildFullName(
+ nvfirst->getString(), nvlast->getString());
+ }
+ }
+
+ if(!source_name.empty())
+ {
+ if (gAgent.getBusy()
+ || LLMuteList::getInstance()->isMuted(source_id, source_name, LLMute::flagTextChat))
+ {
+ // automatically decline offer
+ LLNotifications::instance().forceResponse(LLNotification::Params("OfferCallingCard").payload(payload), 1);
+ }
+ else
+ {
+ args["NAME"] = source_name;
+ LLNotificationsUtil::add("OfferCallingCard", args, payload);
+ }
+ }
+ else
+ {
+ LL_WARNS("Messaging") << "Calling card offer from an unknown source." << LL_ENDL;
+ }
+}
+
+void process_accept_callingcard(LLMessageSystem* msg, void**)
+{
+ LLNotificationsUtil::add("CallingCardAccepted");
+}
+
+void process_decline_callingcard(LLMessageSystem* msg, void**)
+{
+ LLNotificationsUtil::add("CallingCardDeclined");
+}
+
+class ChatTranslationReceiver : public LLTranslate::TranslationReceiver
+{
+public :
+ ChatTranslationReceiver(const std::string &from_lang, const std::string &to_lang, const std::string &mesg,
+ const LLChat &chat, const LLSD &toast_args)
+ : LLTranslate::TranslationReceiver(from_lang, to_lang),
+ m_chat(chat),
+ m_toastArgs(toast_args),
+ m_origMesg(mesg)
+ {
+ }
+
+ static boost::intrusive_ptr<ChatTranslationReceiver> build(const std::string &from_lang, const std::string &to_lang, const std::string &mesg, const LLChat &chat, const LLSD &toast_args)
+ {
+ return boost::intrusive_ptr<ChatTranslationReceiver>(new ChatTranslationReceiver(from_lang, to_lang, mesg, chat, toast_args));
+ }
+
+protected:
+ void handleResponse(const std::string &translation, const std::string &detected_language)
+ {
+ // filter out non-interesting responeses
+ if ( !translation.empty()
+ && (m_toLang != detected_language)
+ && (LLStringUtil::compareInsensitive(translation, m_origMesg) != 0) )
+ {
+ m_chat.mText += " (" + translation + ")";
+ }
+
+ LLNotificationsUI::LLNotificationManager::instance().onChat(m_chat, m_toastArgs);
+ }
+
+ void handleFailure()
+ {
+ LLTranslate::TranslationReceiver::handleFailure();
+ m_chat.mText += " (?)";
+
+ LLNotificationsUI::LLNotificationManager::instance().onChat(m_chat, m_toastArgs);
+ }
+
+private:
+ LLChat m_chat;
+ std::string m_origMesg;
+ LLSD m_toastArgs;
+};
+void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
+{
+ LLChat chat;
+ std::string mesg;
+ std::string from_name;
+ U8 source_temp;
+ U8 type_temp;
+ U8 audible_temp;
+ LLColor4 color(1.0f, 1.0f, 1.0f, 1.0f);
+ LLUUID from_id;
+ LLUUID owner_id;
+ BOOL is_owned_by_me = FALSE;
+ LLViewerObject* chatter;
+
+ msg->getString("ChatData", "FromName", from_name);
+
+ msg->getUUID("ChatData", "SourceID", from_id);
+ chat.mFromID = from_id;
+
+ // Object owner for objects
+ msg->getUUID("ChatData", "OwnerID", owner_id);
+
+ msg->getU8Fast(_PREHASH_ChatData, _PREHASH_SourceType, source_temp);
+ chat.mSourceType = (EChatSourceType)source_temp;
+
+ msg->getU8("ChatData", "ChatType", type_temp);
+ chat.mChatType = (EChatType)type_temp;
+
+ msg->getU8Fast(_PREHASH_ChatData, _PREHASH_Audible, audible_temp);
+ chat.mAudible = (EChatAudible)audible_temp;
+
+ chat.mTime = LLFrameTimer::getElapsedSeconds();
+
+ // IDEVO Correct for new-style "Resident" names
+ if (chat.mSourceType == CHAT_SOURCE_AGENT)
+ {
+ // I don't know if it's OK to change this here, if
+ // anything downstream does lookups by name, for instance
+
+ LLAvatarName av_name;
+ if (LLAvatarNameCache::get(from_id, &av_name))
+ {
+ chat.mFromName = av_name.mDisplayName;
+ }
+ else
+ {
+ chat.mFromName = LLCacheName::cleanFullName(from_name);
+ }
+ }
+ else
+ {
+ chat.mFromName = from_name;
+ }
+
+ BOOL is_busy = gAgent.getBusy();
+
+ BOOL is_muted = FALSE;
+ BOOL is_linden = FALSE;
+ is_muted = LLMuteList::getInstance()->isMuted(
+ from_id,
+ from_name,
+ LLMute::flagTextChat)
+ || LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagTextChat);
+ is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT &&
+ LLMuteList::getInstance()->isLinden(from_name);
+
+ BOOL is_audible = (CHAT_AUDIBLE_FULLY == chat.mAudible);
+ chatter = gObjectList.findObject(from_id);
+ if (chatter)
+ {
+ chat.mPosAgent = chatter->getPositionAgent();
+
+ // Make swirly things only for talking objects. (not script debug messages, though)
+ if (chat.mSourceType == CHAT_SOURCE_OBJECT
+ && chat.mChatType != CHAT_TYPE_DEBUG_MSG
+ && gSavedSettings.getBOOL("EffectScriptChatParticles") )
+ {
+ LLPointer<LLViewerPartSourceChat> psc = new LLViewerPartSourceChat(chatter->getPositionAgent());
+ psc->setSourceObject(chatter);
+ psc->setColor(color);
+ //We set the particles to be owned by the object's owner,
+ //just in case they should be muted by the mute list
+ psc->setOwnerUUID(owner_id);
+ LLViewerPartSim::getInstance()->addPartSource(psc);
+ }
+
+ // record last audible utterance
+ if (is_audible
+ && (is_linden || (!is_muted && !is_busy)))
+ {
+ if (chat.mChatType != CHAT_TYPE_START
+ && chat.mChatType != CHAT_TYPE_STOP)
+ {
+ gAgent.heardChat(chat.mFromID);
+ }
+ }
+
+ is_owned_by_me = chatter->permYouOwner();
+ }
+
+ if (is_audible)
+ {
+ BOOL visible_in_chat_bubble = FALSE;
+ std::string verb;
+
+ color.setVec(1.f,1.f,1.f,1.f);
+ msg->getStringFast(_PREHASH_ChatData, _PREHASH_Message, mesg);
+
+ BOOL ircstyle = FALSE;
+
+ // Look for IRC-style emotes here so chatbubbles work
+ std::string prefix = mesg.substr(0, 4);
+ if (prefix == "/me " || prefix == "/me'")
+ {
+ ircstyle = TRUE;
+ }
+ chat.mText = mesg;
+
+ // Look for the start of typing so we can put "..." in the bubbles.
+ if (CHAT_TYPE_START == chat.mChatType)
+ {
+ LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, TRUE);
+
+ // Might not have the avatar constructed yet, eg on login.
+ if (chatter && chatter->isAvatar())
+ {
+ ((LLVOAvatar*)chatter)->startTyping();
+ }
+ return;
+ }
+ else if (CHAT_TYPE_STOP == chat.mChatType)
+ {
+ LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE);
+
+ // Might not have the avatar constructed yet, eg on login.
+ if (chatter && chatter->isAvatar())
+ {
+ ((LLVOAvatar*)chatter)->stopTyping();
+ }
+ return;
+ }
+
+ // Look for IRC-style emotes
+ if (ircstyle)
+ {
+ // set CHAT_STYLE_IRC to avoid adding Avatar Name as author of message. See EXT-656
+ chat.mChatStyle = CHAT_STYLE_IRC;
+
+ // Do nothing, ircstyle is fixed above for chat bubbles
+ }
+ else
+ {
+ switch(chat.mChatType)
+ {
+ case CHAT_TYPE_WHISPER:
+ verb = LLTrans::getString("whisper") + " ";
+ break;
+ case CHAT_TYPE_DEBUG_MSG:
+ case CHAT_TYPE_OWNER:
+ case CHAT_TYPE_NORMAL:
+ verb = "";
+ break;
+ case CHAT_TYPE_SHOUT:
+ verb = LLTrans::getString("shout") + " ";
+ break;
+ case CHAT_TYPE_START:
+ case CHAT_TYPE_STOP:
+ LL_WARNS("Messaging") << "Got chat type start/stop in main chat processing." << LL_ENDL;
+ break;
+ default:
+ LL_WARNS("Messaging") << "Unknown type " << chat.mChatType << " in chat!" << LL_ENDL;
+ verb = "";
+ break;
+ }
+
+
+ chat.mText = "";
+ chat.mText += verb;
+ chat.mText += mesg;
+ }
+
+ // We have a real utterance now, so can stop showing "..." and proceed.
+ if (chatter && chatter->isAvatar())
+ {
+ LLLocalSpeakerMgr::getInstance()->setSpeakerTyping(from_id, FALSE);
+ ((LLVOAvatar*)chatter)->stopTyping();
+
+ if (!is_muted && !is_busy)
+ {
+ visible_in_chat_bubble = gSavedSettings.getBOOL("UseChatBubbles");
+ std::string formated_msg = "";
+ LLViewerChat::formatChatMsg(chat, formated_msg);
+ LLChat chat_bubble = chat;
+ chat_bubble.mText = formated_msg;
+ ((LLVOAvatar*)chatter)->addChat(chat_bubble);
+ }
+ }
+
+ if (chatter)
+ {
+ chat.mPosAgent = chatter->getPositionAgent();
+ }
+
+ // truth table:
+ // LINDEN BUSY MUTED OWNED_BY_YOU TASK DISPLAY STORE IN HISTORY
+ // F F F F * Yes Yes
+ // F F F T * Yes Yes
+ // F F T F * No No
+ // F F T T * No No
+ // F T F F * No Yes
+ // F T F T * Yes Yes
+ // F T T F * No No
+ // F T T T * No No
+ // T * * * F Yes Yes
+
+ chat.mMuted = is_muted && !is_linden;
+
+ // pass owner_id to chat so that we can display the remote
+ // object inspect for an object that is chatting with you
+ LLSD args;
+ args["type"] = LLNotificationsUI::NT_NEARBYCHAT;
+ chat.mOwnerID = owner_id;
+
+ if (gSavedSettings.getBOOL("TranslateChat") && chat.mSourceType != CHAT_SOURCE_SYSTEM)
+ {
+ if (chat.mChatStyle == CHAT_STYLE_IRC)
+ {
+ mesg = mesg.substr(4, std::string::npos);
+ }
+ const std::string from_lang = ""; // leave empty to trigger autodetect
+ const std::string to_lang = LLTranslate::getTranslateLanguage();
+
+ LLHTTPClient::ResponderPtr result = ChatTranslationReceiver::build(from_lang, to_lang, mesg, chat, args);
+ LLTranslate::translateMessage(result, from_lang, to_lang, mesg);
+ }
+ else
+ {
+ LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args);
+ }
+ }
+}
+
+
+// Simulator we're on is informing the viewer that the agent
+// is starting to teleport (perhaps to another sim, perhaps to the
+// same sim). If we initiated the teleport process by sending some kind
+// of TeleportRequest, then this info is redundant, but if the sim
+// initiated the teleport (via a script call, being killed, etc.)
+// then this info is news to us.
+void process_teleport_start(LLMessageSystem *msg, void**)
+{
+ // on teleport, don't tell them about destination guide anymore
+ LLFirstUse::notUsingDestinationGuide(false);
+ U32 teleport_flags = 0x0;
+ msg->getU32("Info", "TeleportFlags", teleport_flags);
+
+ LL_DEBUGS("Messaging") << "Got TeleportStart with TeleportFlags=" << teleport_flags << ". gTeleportDisplay: " << gTeleportDisplay << ", gAgent.mTeleportState: " << gAgent.getTeleportState() << LL_ENDL;
+
+ if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL)
+ {
+ gViewerWindow->setProgressCancelButtonVisible(FALSE);
+ }
+ else
+ {
+ gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Cancel"));
+ }
+
+ // Freeze the UI and show progress bar
+ // Note: could add data here to differentiate between normal teleport and death.
+
+ if( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE )
+ {
+ gTeleportDisplay = TRUE;
+ gAgent.setTeleportState( LLAgent::TELEPORT_START );
+ make_ui_sound("UISndTeleportOut");
+
+ LL_INFOS("Messaging") << "Teleport initiated by remote TeleportStart message with TeleportFlags: " << teleport_flags << LL_ENDL;
+ // Don't call LLFirstUse::useTeleport here because this could be
+ // due to being killed, which would send you home, not to a Telehub
+ }
+}
+
+void process_teleport_progress(LLMessageSystem* msg, void**)
+{
+ LLUUID agent_id;
+ msg->getUUID("AgentData", "AgentID", agent_id);
+ if((gAgent.getID() != agent_id)
+ || (gAgent.getTeleportState() == LLAgent::TELEPORT_NONE))
+ {
+ LL_WARNS("Messaging") << "Unexpected teleport progress message." << LL_ENDL;
+ return;
+ }
+ U32 teleport_flags = 0x0;
+ msg->getU32("Info", "TeleportFlags", teleport_flags);
+ if (teleport_flags & TELEPORT_FLAGS_DISABLE_CANCEL)
+ {
+ gViewerWindow->setProgressCancelButtonVisible(FALSE);
+ }
+ else
+ {
+ gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Cancel"));
+ }
+ std::string buffer;
+ msg->getString("Info", "Message", buffer);
+ LL_DEBUGS("Messaging") << "teleport progress: " << buffer << LL_ENDL;
+
+ //Sorta hacky...default to using simulator raw messages
+ //if we don't find the coresponding mapping in our progress mappings
+ std::string message = buffer;
+
+ if (LLAgent::sTeleportProgressMessages.find(buffer) !=
+ LLAgent::sTeleportProgressMessages.end() )
+ {
+ message = LLAgent::sTeleportProgressMessages[buffer];
+ }
+
+ gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages[message]);
+}
+
+class LLFetchInWelcomeArea : public LLInventoryFetchDescendentsObserver
+{
+public:
+ LLFetchInWelcomeArea(const uuid_vec_t &ids) :
+ LLInventoryFetchDescendentsObserver(ids)
+ {}
+ virtual void done()
+ {
+ LLIsType is_landmark(LLAssetType::AT_LANDMARK);
+ LLIsType is_card(LLAssetType::AT_CALLINGCARD);
+
+ LLInventoryModel::cat_array_t card_cats;
+ LLInventoryModel::item_array_t card_items;
+ LLInventoryModel::cat_array_t land_cats;
+ LLInventoryModel::item_array_t land_items;
+
+ uuid_vec_t::iterator it = mComplete.begin();
+ uuid_vec_t::iterator end = mComplete.end();
+ for(; it != end; ++it)
+ {
+ gInventory.collectDescendentsIf(
+ (*it),
+ land_cats,
+ land_items,
+ LLInventoryModel::EXCLUDE_TRASH,
+ is_landmark);
+ gInventory.collectDescendentsIf(
+ (*it),
+ card_cats,
+ card_items,
+ LLInventoryModel::EXCLUDE_TRASH,
+ is_card);
+ }
+ LLSD args;
+ if ( land_items.count() > 0 )
+ { // Show notification that they can now teleport to landmarks. Use a random landmark from the inventory
+ S32 random_land = ll_rand( land_items.count() - 1 );
+ args["NAME"] = land_items[random_land]->getName();
+ LLNotificationsUtil::add("TeleportToLandmark",args);
+ }
+ if ( card_items.count() > 0 )
+ { // Show notification that they can now contact people. Use a random calling card from the inventory
+ S32 random_card = ll_rand( card_items.count() - 1 );
+ args["NAME"] = card_items[random_card]->getName();
+ LLNotificationsUtil::add("TeleportToPerson",args);
+ }
+
+ gInventory.removeObserver(this);
+ delete this;
+ }
+};
+
+
+
+class LLPostTeleportNotifiers : public LLEventTimer
+{
+public:
+ LLPostTeleportNotifiers();
+ virtual ~LLPostTeleportNotifiers();
+
+ //function to be called at the supplied frequency
+ virtual BOOL tick();
+};
+
+LLPostTeleportNotifiers::LLPostTeleportNotifiers() : LLEventTimer( 2.0 )
+{
+};
+
+LLPostTeleportNotifiers::~LLPostTeleportNotifiers()
+{
+}
+
+BOOL LLPostTeleportNotifiers::tick()
+{
+ BOOL all_done = FALSE;
+ if ( gAgent.getTeleportState() == LLAgent::TELEPORT_NONE )
+ {
+ // get callingcards and landmarks available to the user arriving.
+ uuid_vec_t folders;
+ const LLUUID callingcard_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD);
+ if(callingcard_id.notNull())
+ folders.push_back(callingcard_id);
+ const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
+ if(folder_id.notNull())
+ folders.push_back(folder_id);
+ if(!folders.empty())
+ {
+ LLFetchInWelcomeArea* fetcher = new LLFetchInWelcomeArea(folders);
+ fetcher->startFetch();
+ if(fetcher->isFinished())
+ {
+ fetcher->done();
+ }
+ else
+ {
+ gInventory.addObserver(fetcher);
+ }
+ }
+ all_done = TRUE;
+ }
+
+ return all_done;
+}
+
+
+
+// Teleport notification from the simulator
+// We're going to pretend to be a new agent
+void process_teleport_finish(LLMessageSystem* msg, void**)
+{
+ LL_DEBUGS("Messaging") << "Got teleport location message" << LL_ENDL;
+ LLUUID agent_id;
+ msg->getUUIDFast(_PREHASH_Info, _PREHASH_AgentID, agent_id);
+ if (agent_id != gAgent.getID())
+ {
+ LL_WARNS("Messaging") << "Got teleport notification for wrong agent!" << LL_ENDL;
+ return;
+ }
+
+ // Teleport is finished; it can't be cancelled now.
+ gViewerWindow->setProgressCancelButtonVisible(FALSE);
+
+ // Do teleport effect for where you're leaving
+ // VEFFECT: TeleportStart
+ LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
+ effectp->setPositionGlobal(gAgent.getPositionGlobal());
+ effectp->setColor(LLColor4U(gAgent.getEffectColor()));
+ LLHUDManager::getInstance()->sendEffects();
+
+ U32 location_id;
+ U32 sim_ip;
+ U16 sim_port;
+ LLVector3 pos, look_at;
+ U64 region_handle;
+ msg->getU32Fast(_PREHASH_Info, _PREHASH_LocationID, location_id);
+ msg->getIPAddrFast(_PREHASH_Info, _PREHASH_SimIP, sim_ip);
+ msg->getIPPortFast(_PREHASH_Info, _PREHASH_SimPort, sim_port);
+ //msg->getVector3Fast(_PREHASH_Info, _PREHASH_Position, pos);
+ //msg->getVector3Fast(_PREHASH_Info, _PREHASH_LookAt, look_at);
+ msg->getU64Fast(_PREHASH_Info, _PREHASH_RegionHandle, region_handle);
+ U32 teleport_flags;
+ msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags);
+
+
+ std::string seedCap;
+ msg->getStringFast(_PREHASH_Info, _PREHASH_SeedCapability, seedCap);
+
+ // update home location if we are teleporting out of prelude - specific to teleporting to welcome area
+ if((teleport_flags & TELEPORT_FLAGS_SET_HOME_TO_TARGET)
+ && (!gAgent.isGodlike()))
+ {
+ gAgent.setHomePosRegion(region_handle, pos);
+
+ // Create a timer that will send notices when teleporting is all finished. Since this is
+ // based on the LLEventTimer class, it will be managed by that class and not orphaned or leaked.
+ new LLPostTeleportNotifiers();
+ }
+
+ LLHost sim_host(sim_ip, sim_port);
+
+ // Viewer trusts the simulator.
+ gMessageSystem->enableCircuit(sim_host, TRUE);
+ LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host);
+
+/*
+ // send camera update to new region
+ gAgentCamera.updateCamera();
+
+ // likewise make sure the camera is behind the avatar
+ gAgentCamera.resetView(TRUE);
+ LLVector3 shift_vector = regionp->getPosRegionFromGlobal(gAgent.getRegion()->getOriginGlobal());
+ gAgent.setRegion(regionp);
+ gObjectList.shiftObjects(shift_vector);
+
+ if (isAgentAvatarValid())
+ {
+ gAgentAvatarp->clearChatText();
+ gAgentCamera.slamLookAt(look_at);
+ }
+ gAgent.setPositionAgent(pos);
+ gAssetStorage->setUpstream(sim);
+ gCacheName->setUpstream(sim);
+*/
+
+ // now, use the circuit info to tell simulator about us!
+ LL_INFOS("Messaging") << "process_teleport_finish() Enabling "
+ << sim_host << " with code " << msg->mOurCircuitCode << LL_ENDL;
+ msg->newMessageFast(_PREHASH_UseCircuitCode);
+ msg->nextBlockFast(_PREHASH_CircuitCode);
+ msg->addU32Fast(_PREHASH_Code, msg->getOurCircuitCode());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addUUIDFast(_PREHASH_ID, gAgent.getID());
+ msg->sendReliable(sim_host);
+
+ send_complete_agent_movement(sim_host);
+ gAgent.setTeleportState( LLAgent::TELEPORT_MOVING );
+ gAgent.setTeleportMessage(LLAgent::sTeleportProgressMessages["contacting"]);
+
+ regionp->setSeedCapability(seedCap);
+
+ // Don't send camera updates to the new region until we're
+ // actually there...
+
+
+ // Now do teleport effect for where you're going.
+ // VEFFECT: TeleportEnd
+ effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
+ effectp->setPositionGlobal(gAgent.getPositionGlobal());
+
+ effectp->setColor(LLColor4U(gAgent.getEffectColor()));
+ LLHUDManager::getInstance()->sendEffects();
+
+// gTeleportDisplay = TRUE;
+// gTeleportDisplayTimer.reset();
+// gViewerWindow->setShowProgress(TRUE);
+}
+
+// stuff we have to do every time we get an AvatarInitComplete from a sim
+/*
+void process_avatar_init_complete(LLMessageSystem* msg, void**)
+{
+ LLVector3 agent_pos;
+ msg->getVector3Fast(_PREHASH_AvatarData, _PREHASH_Position, agent_pos);
+ agent_movement_complete(msg->getSender(), agent_pos);
+}
+*/
+
+void process_agent_movement_complete(LLMessageSystem* msg, void**)
+{
+ gAgentMovementCompleted = true;
+
+ LLUUID agent_id;
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
+ LLUUID session_id;
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id);
+ if((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id))
+ {
+ LL_WARNS("Messaging") << "Incorrect id in process_agent_movement_complete()"
+ << LL_ENDL;
+ return;
+ }
+
+ LL_DEBUGS("Messaging") << "process_agent_movement_complete()" << LL_ENDL;
+
+ // *TODO: check timestamp to make sure the movement compleation
+ // makes sense.
+ LLVector3 agent_pos;
+ msg->getVector3Fast(_PREHASH_Data, _PREHASH_Position, agent_pos);
+ LLVector3 look_at;
+ msg->getVector3Fast(_PREHASH_Data, _PREHASH_LookAt, look_at);
+ U64 region_handle;
+ msg->getU64Fast(_PREHASH_Data, _PREHASH_RegionHandle, region_handle);
+
+ std::string version_channel;
+ msg->getString("SimData", "ChannelVersion", version_channel);
+
+ if (!isAgentAvatarValid())
+ {
+ // Could happen if you were immediately god-teleported away on login,
+ // maybe other cases. Continue, but warn.
+ LL_WARNS("Messaging") << "agent_movement_complete() with NULL avatarp." << LL_ENDL;
+ }
+
+ F32 x, y;
+ from_region_handle(region_handle, &x, &y);
+ LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromHandle(region_handle);
+ if (!regionp)
+ {
+ if (gAgent.getRegion())
+ {
+ LL_WARNS("Messaging") << "current region " << gAgent.getRegion()->getOriginGlobal() << LL_ENDL;
+ }
+
+ LL_WARNS("Messaging") << "Agent being sent to invalid home region: "
+ << x << ":" << y
+ << " current pos " << gAgent.getPositionGlobal()
+ << LL_ENDL;
+ LLAppViewer::instance()->forceDisconnect(LLTrans::getString("SentToInvalidRegion"));
+ return;
+
+ }
+
+ LL_INFOS("Messaging") << "Changing home region to " << x << ":" << y << LL_ENDL;
+
+ // set our upstream host the new simulator and shuffle things as
+ // appropriate.
+ LLVector3 shift_vector = regionp->getPosRegionFromGlobal(
+ gAgent.getRegion()->getOriginGlobal());
+ gAgent.setRegion(regionp);
+ gObjectList.shiftObjects(shift_vector);
+ gAssetStorage->setUpstream(msg->getSender());
+ gCacheName->setUpstream(msg->getSender());
+ gViewerThrottle.sendToSim();
+ gViewerWindow->sendShapeToSim();
+
+ bool is_teleport = gAgent.getTeleportState() == LLAgent::TELEPORT_MOVING;
+
+ if( is_teleport )
+ {
+ if (gAgent.getTeleportKeepsLookAt())
+ {
+ // *NOTE: the LookAt data we get from the sim here doesn't
+ // seem to be useful, so get it from the camera instead
+ look_at = LLViewerCamera::getInstance()->getAtAxis();
+ }
+ // Force the camera back onto the agent, don't animate.
+ gAgentCamera.setFocusOnAvatar(TRUE, FALSE);
+ gAgentCamera.slamLookAt(look_at);
+ gAgentCamera.updateCamera();
+
+ gAgent.setTeleportState( LLAgent::TELEPORT_START_ARRIVAL );
+
+ // set the appearance on teleport since the new sim does not
+ // know what you look like.
+ gAgent.sendAgentSetAppearance();
+
+ if (isAgentAvatarValid())
+ {
+ // Chat the "back" SLURL. (DEV-4907)
+
+ LLSLURL slurl;
+ gAgent.getTeleportSourceSLURL(slurl);
+ LLSD substitution = LLSD().with("[T_SLURL]", slurl.getSLURLString());
+ std::string completed_from = LLAgent::sTeleportProgressMessages["completed_from"];
+ LLStringUtil::format(completed_from, substitution);
+
+ LLSD args;
+ args["MESSAGE"] = completed_from;
+ LLNotificationsUtil::add("SystemMessageTip", args);
+
+ // Set the new position
+ gAgentAvatarp->setPositionAgent(agent_pos);
+ gAgentAvatarp->clearChat();
+ gAgentAvatarp->slamPosition();
+ }
+ }
+ else
+ {
+ // This is initial log-in or a region crossing
+ gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
+
+ if(LLStartUp::getStartupState() < STATE_STARTED)
+ { // This is initial log-in, not a region crossing:
+ // Set the camera looking ahead of the AV so send_agent_update() below
+ // will report the correct location to the server.
+ LLVector3 look_at_point = look_at;
+ look_at_point = agent_pos + look_at_point.rotVec(gAgent.getQuat());
+
+ static LLVector3 up_direction(0.0f, 0.0f, 1.0f);
+ LLViewerCamera::getInstance()->lookAt(agent_pos, look_at_point, up_direction);
+ }
+ }
+
+ if ( LLTracker::isTracking(NULL) )
+ {
+ // Check distance to beacon, if < 5m, remove beacon
+ LLVector3d beacon_pos = LLTracker::getTrackedPositionGlobal();
+ LLVector3 beacon_dir(agent_pos.mV[VX] - (F32)fmod(beacon_pos.mdV[VX], 256.0), agent_pos.mV[VY] - (F32)fmod(beacon_pos.mdV[VY], 256.0), 0);
+ if (beacon_dir.magVecSquared() < 25.f)
+ {
+ LLTracker::stopTracking(NULL);
+ }
+ else if ( is_teleport && !gAgent.getTeleportKeepsLookAt() )
+ {
+ //look at the beacon
+ LLVector3 global_agent_pos = agent_pos;
+ global_agent_pos[0] += x;
+ global_agent_pos[1] += y;
+ look_at = (LLVector3)beacon_pos - global_agent_pos;
+ look_at.normVec();
+ gAgentCamera.slamLookAt(look_at);
+ }
+ }
+
+ // TODO: Put back a check for flying status! DK 12/19/05
+ // Sim tells us whether the new position is off the ground
+ /*
+ if (teleport_flags & TELEPORT_FLAGS_IS_FLYING)
+ {
+ gAgent.setFlying(TRUE);
+ }
+ else
+ {
+ gAgent.setFlying(FALSE);
+ }
+ */
+
+ send_agent_update(TRUE, TRUE);
+
+ if (gAgent.getRegion()->getBlockFly())
+ {
+ gAgent.setFlying(gAgent.canFly());
+ }
+
+ // force simulator to recognize busy state
+ if (gAgent.getBusy())
+ {
+ gAgent.setBusy();
+ }
+ else
+ {
+ gAgent.clearBusy();
+ }
+
+ if (isAgentAvatarValid())
+ {
+ gAgentAvatarp->mFootPlane.clearVec();
+ }
+
+ // send walk-vs-run status
+ gAgent.sendWalkRun(gAgent.getRunning() || gAgent.getAlwaysRun());
+
+ // If the server version has changed, display an info box and offer
+ // to display the release notes, unless this is the initial log in.
+ if (gLastVersionChannel == version_channel)
+ {
+ return;
+ }
+
+ gLastVersionChannel = version_channel;
+}
+
+void process_crossed_region(LLMessageSystem* msg, void**)
+{
+ LLUUID agent_id;
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
+ LLUUID session_id;
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id);
+ if((gAgent.getID() != agent_id) || (gAgent.getSessionID() != session_id))
+ {
+ LL_WARNS("Messaging") << "Incorrect id in process_crossed_region()"
+ << LL_ENDL;
+ return;
+ }
+ LL_INFOS("Messaging") << "process_crossed_region()" << LL_ENDL;
+ gAgentAvatarp->resetRegionCrossingTimer();
+
+ U32 sim_ip;
+ msg->getIPAddrFast(_PREHASH_RegionData, _PREHASH_SimIP, sim_ip);
+ U16 sim_port;
+ msg->getIPPortFast(_PREHASH_RegionData, _PREHASH_SimPort, sim_port);
+ LLHost sim_host(sim_ip, sim_port);
+ U64 region_handle;
+ msg->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle);
+
+ std::string seedCap;
+ msg->getStringFast(_PREHASH_RegionData, _PREHASH_SeedCapability, seedCap);
+
+ send_complete_agent_movement(sim_host);
+
+ LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host);
+ regionp->setSeedCapability(seedCap);
+}
+
+
+
+// Sends avatar and camera information to simulator.
+// Sent roughly once per frame, or 20 times per second, whichever is less often
+
+const F32 THRESHOLD_HEAD_ROT_QDOT = 0.9997f; // ~= 2.5 degrees -- if its less than this we need to update head_rot
+const F32 MAX_HEAD_ROT_QDOT = 0.99999f; // ~= 0.5 degrees -- if its greater than this then no need to update head_rot
+ // between these values we delay the updates (but no more than one second)
+
+static LLFastTimer::DeclareTimer FTM_AGENT_UPDATE_SEND("Send Message");
+
+void send_agent_update(BOOL force_send, BOOL send_reliable)
+{
+ if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE)
+ {
+ // We don't care if they want to send an agent update, they're not allowed to until the simulator
+ // that's the target is ready to receive them (after avatar_init_complete is received)
+ return;
+ }
+
+ // We have already requested to log out. Don't send agent updates.
+ if(LLAppViewer::instance()->logoutRequestSent())
+ {
+ return;
+ }
+
+ // no region to send update to
+ if(gAgent.getRegion() == NULL)
+ {
+ return;
+ }
+
+ const F32 TRANSLATE_THRESHOLD = 0.01f;
+
+ // NOTA BENE: This is (intentionally?) using the small angle sine approximation to test for rotation
+ // Plus, there is an extra 0.5 in the mix since the perpendicular between last_camera_at and getAtAxis() bisects cam_rot_change
+ // Thus, we're actually testing against 0.2 degrees
+ const F32 ROTATION_THRESHOLD = 0.1f * 2.f*F_PI/360.f; // Rotation thresh 0.2 deg, see note above
+
+ const U8 DUP_MSGS = 1; // HACK! number of times to repeat data on motionless agent
+
+ // Store data on last sent update so that if no changes, no send
+ static LLVector3 last_camera_pos_agent,
+ last_camera_at,
+ last_camera_left,
+ last_camera_up;
+
+ static LLVector3 cam_center_chg,
+ cam_rot_chg;
+
+ static LLQuaternion last_head_rot;
+ static U32 last_control_flags = 0;
+ static U8 last_render_state;
+ static U8 duplicate_count = 0;
+ static F32 head_rot_chg = 1.0;
+ static U8 last_flags;
+
+ LLMessageSystem *msg = gMessageSystem;
+ LLVector3 camera_pos_agent; // local to avatar's region
+ U8 render_state;
+
+ LLQuaternion body_rotation = gAgent.getFrameAgent().getQuaternion();
+ LLQuaternion head_rotation = gAgent.getHeadRotation();
+
+ camera_pos_agent = gAgentCamera.getCameraPositionAgent();
+
+ render_state = gAgent.getRenderState();
+
+ U32 control_flag_change = 0;
+ U8 flag_change = 0;
+
+ cam_center_chg = last_camera_pos_agent - camera_pos_agent;
+ cam_rot_chg = last_camera_at - LLViewerCamera::getInstance()->getAtAxis();
+
+ // If a modifier key is held down, turn off
+ // LBUTTON and ML_LBUTTON so that using the camera (alt-key) doesn't
+ // trigger a control event.
+ U32 control_flags = gAgent.getControlFlags();
+ MASK key_mask = gKeyboard->currentMask(TRUE);
+ if (key_mask & MASK_ALT || key_mask & MASK_CONTROL)
+ {
+ control_flags &= ~( AGENT_CONTROL_LBUTTON_DOWN |
+ AGENT_CONTROL_ML_LBUTTON_DOWN );
+ control_flags |= AGENT_CONTROL_LBUTTON_UP |
+ AGENT_CONTROL_ML_LBUTTON_UP ;
+ }
+
+ control_flag_change = last_control_flags ^ control_flags;
+
+ U8 flags = AU_FLAGS_NONE;
+ if (gAgent.isGroupTitleHidden())
+ {
+ flags |= AU_FLAGS_HIDETITLE;
+ }
+ if (gAgent.getAutoPilot())
+ {
+ flags |= AU_FLAGS_CLIENT_AUTOPILOT;
+ }
+
+ flag_change = last_flags ^ flags;
+
+ head_rot_chg = dot(last_head_rot, head_rotation);
+
+ if (force_send ||
+ (cam_center_chg.magVec() > TRANSLATE_THRESHOLD) ||
+ (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT) ||
+ (last_render_state != render_state) ||
+ (cam_rot_chg.magVec() > ROTATION_THRESHOLD) ||
+ control_flag_change != 0 ||
+ flag_change != 0)
+ {
+/*
+ if (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT)
+ {
+ //LL_INFOS("Messaging") << "head rot " << head_rotation << LL_ENDL;
+ LL_INFOS("Messaging") << "head_rot_chg = " << head_rot_chg << LL_ENDL;
+ }
+ if (cam_rot_chg.magVec() > ROTATION_THRESHOLD)
+ {
+ LL_INFOS("Messaging") << "cam rot " << cam_rot_chg.magVec() << LL_ENDL;
+ }
+ if (cam_center_chg.magVec() > TRANSLATE_THRESHOLD)
+ {
+ LL_INFOS("Messaging") << "cam center " << cam_center_chg.magVec() << LL_ENDL;
+ }
+// if (drag_delta_chg.magVec() > TRANSLATE_THRESHOLD)
+// {
+// LL_INFOS("Messaging") << "drag delta " << drag_delta_chg.magVec() << LL_ENDL;
+// }
+ if (control_flag_change)
+ {
+ LL_INFOS("Messaging") << "dcf = " << control_flag_change << LL_ENDL;
+ }
+*/
+
+ duplicate_count = 0;
+ }
+ else
+ {
+ duplicate_count++;
+
+ if (head_rot_chg < MAX_HEAD_ROT_QDOT && duplicate_count < AGENT_UPDATES_PER_SECOND)
+ {
+ // The head_rotation is sent for updating things like attached guns.
+ // We only trigger a new update when head_rotation deviates beyond
+ // some threshold from the last update, however this can break fine
+ // adjustments when trying to aim an attached gun, so what we do here
+ // (where we would normally skip sending an update when nothing has changed)
+ // is gradually reduce the threshold to allow a better update to
+ // eventually get sent... should update to within 0.5 degrees in less
+ // than a second.
+ if (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT + (MAX_HEAD_ROT_QDOT - THRESHOLD_HEAD_ROT_QDOT) * duplicate_count / AGENT_UPDATES_PER_SECOND)
+ {
+ duplicate_count = 0;
+ }
+ else
+ {
+ return;
+ }
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ if (duplicate_count < DUP_MSGS && !gDisconnected)
+ {
+ LLFastTimer t(FTM_AGENT_UPDATE_SEND);
+ // Build the message
+ msg->newMessageFast(_PREHASH_AgentUpdate);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addQuatFast(_PREHASH_BodyRotation, body_rotation);
+ msg->addQuatFast(_PREHASH_HeadRotation, head_rotation);
+ msg->addU8Fast(_PREHASH_State, render_state);
+ msg->addU8Fast(_PREHASH_Flags, flags);
+
+// if (camera_pos_agent.mV[VY] > 255.f)
+// {
+// LL_INFOS("Messaging") << "Sending camera center " << camera_pos_agent << LL_ENDL;
+// }
+
+ msg->addVector3Fast(_PREHASH_CameraCenter, camera_pos_agent);
+ msg->addVector3Fast(_PREHASH_CameraAtAxis, LLViewerCamera::getInstance()->getAtAxis());
+ msg->addVector3Fast(_PREHASH_CameraLeftAxis, LLViewerCamera::getInstance()->getLeftAxis());
+ msg->addVector3Fast(_PREHASH_CameraUpAxis, LLViewerCamera::getInstance()->getUpAxis());
+ msg->addF32Fast(_PREHASH_Far, gAgentCamera.mDrawDistance);
+
+ msg->addU32Fast(_PREHASH_ControlFlags, control_flags);
+
+ if (gDebugClicks)
+ {
+ if (control_flags & AGENT_CONTROL_LBUTTON_DOWN)
+ {
+ LL_INFOS("Messaging") << "AgentUpdate left button down" << LL_ENDL;
+ }
+
+ if (control_flags & AGENT_CONTROL_LBUTTON_UP)
+ {
+ LL_INFOS("Messaging") << "AgentUpdate left button up" << LL_ENDL;
+ }
+ }
+
+ gAgent.enableControlFlagReset();
+
+ if (!send_reliable)
+ {
+ gAgent.sendMessage();
+ }
+ else
+ {
+ gAgent.sendReliableMessage();
+ }
+
+// LL_DEBUGS("Messaging") << "agent " << avatar_pos_agent << " cam " << camera_pos_agent << LL_ENDL;
+
+ // Copy the old data
+ last_head_rot = head_rotation;
+ last_render_state = render_state;
+ last_camera_pos_agent = camera_pos_agent;
+ last_camera_at = LLViewerCamera::getInstance()->getAtAxis();
+ last_camera_left = LLViewerCamera::getInstance()->getLeftAxis();
+ last_camera_up = LLViewerCamera::getInstance()->getUpAxis();
+ last_control_flags = control_flags;
+ last_flags = flags;
+ }
+}
+
+
+
+// *TODO: Remove this dependency, or figure out a better way to handle
+// this hack.
+extern U32 gObjectBits;
+
+void process_object_update(LLMessageSystem *mesgsys, void **user_data)
+{
+ LLMemType mt(LLMemType::MTYPE_OBJECT);
+ // Update the data counters
+ if (mesgsys->getReceiveCompressedSize())
+ {
+ gObjectBits += mesgsys->getReceiveCompressedSize() * 8;
+ }
+ else
+ {
+ gObjectBits += mesgsys->getReceiveSize() * 8;
+ }
+
+ // Update the object...
+ gObjectList.processObjectUpdate(mesgsys, user_data, OUT_FULL);
+}
+
+void process_compressed_object_update(LLMessageSystem *mesgsys, void **user_data)
+{
+ LLMemType mt(LLMemType::MTYPE_OBJECT);
+ // Update the data counters
+ if (mesgsys->getReceiveCompressedSize())
+ {
+ gObjectBits += mesgsys->getReceiveCompressedSize() * 8;
+ }
+ else
+ {
+ gObjectBits += mesgsys->getReceiveSize() * 8;
+ }
+
+ // Update the object...
+ gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_FULL_COMPRESSED);
+}
+
+void process_cached_object_update(LLMessageSystem *mesgsys, void **user_data)
+{
+ LLMemType mt(LLMemType::MTYPE_OBJECT);
+ // Update the data counters
+ if (mesgsys->getReceiveCompressedSize())
+ {
+ gObjectBits += mesgsys->getReceiveCompressedSize() * 8;
+ }
+ else
+ {
+ gObjectBits += mesgsys->getReceiveSize() * 8;
+ }
+
+ // Update the object...
+ gObjectList.processCachedObjectUpdate(mesgsys, user_data, OUT_FULL_CACHED);
+}
+
+
+void process_terse_object_update_improved(LLMessageSystem *mesgsys, void **user_data)
+{
+ LLMemType mt(LLMemType::MTYPE_OBJECT);
+ if (mesgsys->getReceiveCompressedSize())
+ {
+ gObjectBits += mesgsys->getReceiveCompressedSize() * 8;
+ }
+ else
+ {
+ gObjectBits += mesgsys->getReceiveSize() * 8;
+ }
+
+ gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_TERSE_IMPROVED);
+}
+
+static LLFastTimer::DeclareTimer FTM_PROCESS_OBJECTS("Process Objects");
+
+
+void process_kill_object(LLMessageSystem *mesgsys, void **user_data)
+{
+ LLFastTimer t(FTM_PROCESS_OBJECTS);
+
+ LLUUID id;
+ U32 local_id;
+ S32 i;
+ S32 num_objects;
+
+ num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData);
+
+ for (i = 0; i < num_objects; i++)
+ {
+ mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i);
+
+ LLViewerObjectList::getUUIDFromLocal(id,
+ local_id,
+ gMessageSystem->getSenderIP(),
+ gMessageSystem->getSenderPort());
+ if (id == LLUUID::null)
+ {
+ LL_DEBUGS("Messaging") << "Unknown kill for local " << local_id << LL_ENDL;
+ gObjectList.mNumUnknownKills++;
+ continue;
+ }
+ else
+ {
+ LL_DEBUGS("Messaging") << "Kill message for local " << local_id << LL_ENDL;
+ }
+
+ LLSelectMgr::getInstance()->removeObjectFromSelections(id);
+
+ // ...don't kill the avatar
+ if (!(id == gAgentID))
+ {
+ LLViewerObject *objectp = gObjectList.findObject(id);
+ if (objectp)
+ {
+ // Display green bubble on kill
+ if ( gShowObjectUpdates )
+ {
+ LLViewerObject* newobject;
+ newobject = gObjectList.createObjectViewer(LL_PCODE_LEGACY_TEXT_BUBBLE, objectp->getRegion());
+
+ LLVOTextBubble* bubble = (LLVOTextBubble*) newobject;
+
+ bubble->mColor.setVec(0.f, 1.f, 0.f, 1.f);
+ bubble->setScale( 2.0f * bubble->getScale() );
+ bubble->setPositionGlobal(objectp->getPositionGlobal());
+ gPipeline.addObject(bubble);
+ }
+
+ // Do the kill
+ gObjectList.killObject(objectp);
+ }
+ else
+ {
+ LL_WARNS("Messaging") << "Object in UUID lookup, but not on object list in kill!" << LL_ENDL;
+ gObjectList.mNumUnknownKills++;
+ }
+ }
+ }
+}
+
+void process_time_synch(LLMessageSystem *mesgsys, void **user_data)
+{
+ LLVector3 sun_direction;
+ LLVector3 sun_ang_velocity;
+ F32 phase;
+ U64 space_time_usec;
+
+ U32 seconds_per_day;
+ U32 seconds_per_year;
+
+ // "SimulatorViewerTimeMessage"
+ mesgsys->getU64Fast(_PREHASH_TimeInfo, _PREHASH_UsecSinceStart, space_time_usec);
+ mesgsys->getU32Fast(_PREHASH_TimeInfo, _PREHASH_SecPerDay, seconds_per_day);
+ mesgsys->getU32Fast(_PREHASH_TimeInfo, _PREHASH_SecPerYear, seconds_per_year);
+
+ // This should eventually be moved to an "UpdateHeavenlyBodies" message
+ mesgsys->getF32Fast(_PREHASH_TimeInfo, _PREHASH_SunPhase, phase);
+ mesgsys->getVector3Fast(_PREHASH_TimeInfo, _PREHASH_SunDirection, sun_direction);
+ mesgsys->getVector3Fast(_PREHASH_TimeInfo, _PREHASH_SunAngVelocity, sun_ang_velocity);
+
+ LLWorld::getInstance()->setSpaceTimeUSec(space_time_usec);
+
+ //LL_DEBUGS("Messaging") << "time_synch() - " << sun_direction << ", " << sun_ang_velocity
+ // << ", " << phase << LL_ENDL;
+
+ gSky.setSunPhase(phase);
+ gSky.setSunTargetDirection(sun_direction, sun_ang_velocity);
+ if (!gNoRender && !(gSavedSettings.getBOOL("SkyOverrideSimSunPosition") || gSky.getOverrideSun()))
+ {
+ gSky.setSunDirection(sun_direction, sun_ang_velocity);
+ }
+}
+
+void process_sound_trigger(LLMessageSystem *msg, void **)
+{
+ if (!gAudiop) return;
+
+ U64 region_handle = 0;
+ F32 gain = 0;
+ LLUUID sound_id;
+ LLUUID owner_id;
+ LLUUID object_id;
+ LLUUID parent_id;
+ LLVector3 pos_local;
+
+ msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_SoundID, sound_id);
+ msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_OwnerID, owner_id);
+ msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_ObjectID, object_id);
+ msg->getUUIDFast(_PREHASH_SoundData, _PREHASH_ParentID, parent_id);
+ msg->getU64Fast(_PREHASH_SoundData, _PREHASH_Handle, region_handle);
+ msg->getVector3Fast(_PREHASH_SoundData, _PREHASH_Position, pos_local);
+ msg->getF32Fast(_PREHASH_SoundData, _PREHASH_Gain, gain);
+
+ // adjust sound location to true global coords
+ LLVector3d pos_global = from_region_handle(region_handle);
+ pos_global.mdV[VX] += pos_local.mV[VX];
+ pos_global.mdV[VY] += pos_local.mV[VY];
+ pos_global.mdV[VZ] += pos_local.mV[VZ];
+
+ // Don't play a trigger sound if you can't hear it due
+ // to parcel "local audio only" settings.
+ if (!LLViewerParcelMgr::getInstance()->canHearSound(pos_global)) return;
+
+ // Don't play sounds triggered by someone you muted.
+ if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return;
+
+ // Don't play sounds from an object you muted
+ if (LLMuteList::getInstance()->isMuted(object_id)) return;
+
+ // Don't play sounds from an object whose parent you muted
+ if (parent_id.notNull()
+ && LLMuteList::getInstance()->isMuted(parent_id))
+ {
+ return;
+ }
+
+ // Don't play sounds from a region with maturity above current agent maturity
+ if( !gAgent.canAccessMaturityInRegion( region_handle ) )
+ {
+ return;
+ }
+
+ gAudiop->triggerSound(sound_id, owner_id, gain, LLAudioEngine::AUDIO_TYPE_SFX, pos_global);
+}
+
+void process_preload_sound(LLMessageSystem *msg, void **user_data)
+{
+ if (!gAudiop)
+ {
+ return;
+ }
+
+ LLUUID sound_id;
+ LLUUID object_id;
+ LLUUID owner_id;
+
+ msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_SoundID, sound_id);
+ msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_id);
+ msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_OwnerID, owner_id);
+
+ LLViewerObject *objectp = gObjectList.findObject(object_id);
+ if (!objectp) return;
+
+ if (LLMuteList::getInstance()->isMuted(object_id)) return;
+ if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return;
+
+ LLAudioSource *sourcep = objectp->getAudioSource(owner_id);
+ if (!sourcep) return;
+
+ LLAudioData *datap = gAudiop->getAudioData(sound_id);
+
+ // Note that I don't actually do any loading of the
+ // audio data into a buffer at this point, as it won't actually
+ // help us out.
+
+ // Don't play sounds from a region with maturity above current agent maturity
+ LLVector3d pos_global = objectp->getPositionGlobal();
+ if (gAgent.canAccessMaturityAtGlobal(pos_global))
+ {
+ // Add audioData starts a transfer internally.
+ sourcep->addAudioData(datap, FALSE);
+}
+}
+
+void process_attached_sound(LLMessageSystem *msg, void **user_data)
+{
+ F32 gain = 0;
+ LLUUID sound_id;
+ LLUUID object_id;
+ LLUUID owner_id;
+ U8 flags;
+
+ msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_SoundID, sound_id);
+ msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_id);
+ msg->getUUIDFast(_PREHASH_DataBlock, _PREHASH_OwnerID, owner_id);
+ msg->getF32Fast(_PREHASH_DataBlock, _PREHASH_Gain, gain);
+ msg->getU8Fast(_PREHASH_DataBlock, _PREHASH_Flags, flags);
+
+ LLViewerObject *objectp = gObjectList.findObject(object_id);
+ if (!objectp)
+ {
+ // we don't know about this object, just bail
+ return;
+ }
+
+ if (LLMuteList::getInstance()->isMuted(object_id)) return;
+
+ if (LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagObjectSounds)) return;
+
+
+ // Don't play sounds from a region with maturity above current agent maturity
+ LLVector3d pos = objectp->getPositionGlobal();
+ if( !gAgent.canAccessMaturityAtGlobal(pos) )
+ {
+ return;
+ }
+
+ objectp->setAttachedSound(sound_id, owner_id, gain, flags);
+}
+
+
+void process_attached_sound_gain_change(LLMessageSystem *mesgsys, void **user_data)
+{
+ F32 gain = 0;
+ LLUUID object_guid;
+ LLViewerObject *objectp = NULL;
+
+ mesgsys->getUUIDFast(_PREHASH_DataBlock, _PREHASH_ObjectID, object_guid);
+
+ if (!((objectp = gObjectList.findObject(object_guid))))
+ {
+ // we don't know about this object, just bail
+ return;
+ }
+
+ mesgsys->getF32Fast(_PREHASH_DataBlock, _PREHASH_Gain, gain);
+
+ objectp->adjustAudioGain(gain);
+}
+
+
+void process_health_message(LLMessageSystem *mesgsys, void **user_data)
+{
+ F32 health;
+
+ mesgsys->getF32Fast(_PREHASH_HealthData, _PREHASH_Health, health);
+
+ if (gStatusBar)
+ {
+ gStatusBar->setHealth((S32)health);
+ }
+}
+
+
+void process_sim_stats(LLMessageSystem *msg, void **user_data)
+{
+ S32 count = msg->getNumberOfBlocks("Stat");
+ for (S32 i = 0; i < count; ++i)
+ {
+ U32 stat_id;
+ F32 stat_value;
+ msg->getU32("Stat", "StatID", stat_id, i);
+ msg->getF32("Stat", "StatValue", stat_value, i);
+ switch (stat_id)
+ {
+ case LL_SIM_STAT_TIME_DILATION:
+ LLViewerStats::getInstance()->mSimTimeDilation.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_FPS:
+ LLViewerStats::getInstance()->mSimFPS.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_PHYSFPS:
+ LLViewerStats::getInstance()->mSimPhysicsFPS.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_AGENTUPS:
+ LLViewerStats::getInstance()->mSimAgentUPS.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_FRAMEMS:
+ LLViewerStats::getInstance()->mSimFrameMsec.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_NETMS:
+ LLViewerStats::getInstance()->mSimNetMsec.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_SIMOTHERMS:
+ LLViewerStats::getInstance()->mSimSimOtherMsec.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_SIMPHYSICSMS:
+ LLViewerStats::getInstance()->mSimSimPhysicsMsec.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_AGENTMS:
+ LLViewerStats::getInstance()->mSimAgentMsec.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_IMAGESMS:
+ LLViewerStats::getInstance()->mSimImagesMsec.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_SCRIPTMS:
+ LLViewerStats::getInstance()->mSimScriptMsec.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_NUMTASKS:
+ LLViewerStats::getInstance()->mSimObjects.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_NUMTASKSACTIVE:
+ LLViewerStats::getInstance()->mSimActiveObjects.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_NUMAGENTMAIN:
+ LLViewerStats::getInstance()->mSimMainAgents.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_NUMAGENTCHILD:
+ LLViewerStats::getInstance()->mSimChildAgents.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_NUMSCRIPTSACTIVE:
+ LLViewerStats::getInstance()->mSimActiveScripts.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_SCRIPT_EPS:
+ LLViewerStats::getInstance()->mSimScriptEPS.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_INPPS:
+ LLViewerStats::getInstance()->mSimInPPS.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_OUTPPS:
+ LLViewerStats::getInstance()->mSimOutPPS.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_PENDING_DOWNLOADS:
+ LLViewerStats::getInstance()->mSimPendingDownloads.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_PENDING_UPLOADS:
+ LLViewerStats::getInstance()->mSimPendingUploads.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_PENDING_LOCAL_UPLOADS:
+ LLViewerStats::getInstance()->mSimPendingLocalUploads.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_TOTAL_UNACKED_BYTES:
+ LLViewerStats::getInstance()->mSimTotalUnackedBytes.addValue(stat_value / 1024.f);
+ break;
+ case LL_SIM_STAT_PHYSICS_PINNED_TASKS:
+ LLViewerStats::getInstance()->mPhysicsPinnedTasks.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_PHYSICS_LOD_TASKS:
+ LLViewerStats::getInstance()->mPhysicsLODTasks.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_SIMPHYSICSSTEPMS:
+ LLViewerStats::getInstance()->mSimSimPhysicsStepMsec.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_SIMPHYSICSSHAPEMS:
+ LLViewerStats::getInstance()->mSimSimPhysicsShapeUpdateMsec.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_SIMPHYSICSOTHERMS:
+ LLViewerStats::getInstance()->mSimSimPhysicsOtherMsec.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_SIMPHYSICSMEMORY:
+ LLViewerStats::getInstance()->mPhysicsMemoryAllocated.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_SIMSPARETIME:
+ LLViewerStats::getInstance()->mSimSpareMsec.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_SIMSLEEPTIME:
+ LLViewerStats::getInstance()->mSimSleepMsec.addValue(stat_value);
+ break;
+ case LL_SIM_STAT_IOPUMPTIME:
+ LLViewerStats::getInstance()->mSimPumpIOMsec.addValue(stat_value);
+ break;
+ default:
+ // Used to be a commented out warning.
+ LL_DEBUGS("Messaging") << "Unknown stat id" << stat_id << LL_ENDL;
+ break;
+ }
+ }
+
+ /*
+ msg->getF32Fast(_PREHASH_Statistics, _PREHASH_PhysicsTimeDilation, time_dilation);
+ LLViewerStats::getInstance()->mSimTDStat.addValue(time_dilation);
+
+ // Process information
+ // { CpuUsage F32 }
+ // { SimMemTotal F32 }
+ // { SimMemRSS F32 }
+ // { ProcessUptime F32 }
+ F32 cpu_usage;
+ F32 sim_mem_total;
+ F32 sim_mem_rss;
+ F32 process_uptime;
+ msg->getF32Fast(_PREHASH_Statistics, _PREHASH_CpuUsage, cpu_usage);
+ msg->getF32Fast(_PREHASH_Statistics, _PREHASH_SimMemTotal, sim_mem_total);
+ msg->getF32Fast(_PREHASH_Statistics, _PREHASH_SimMemRSS, sim_mem_rss);
+ msg->getF32Fast(_PREHASH_Statistics, _PREHASH_ProcessUptime, process_uptime);
+ LLViewerStats::getInstance()->mSimCPUUsageStat.addValue(cpu_usage);
+ LLViewerStats::getInstance()->mSimMemTotalStat.addValue(sim_mem_total);
+ LLViewerStats::getInstance()->mSimMemRSSStat.addValue(sim_mem_rss);
+ */
+
+ //
+ // Various hacks that aren't statistics, but are being handled here.
+ //
+ U32 max_tasks_per_region;
+ U32 region_flags;
+ msg->getU32("Region", "ObjectCapacity", max_tasks_per_region);
+ msg->getU32("Region", "RegionFlags", region_flags);
+
+ LLViewerRegion* regionp = gAgent.getRegion();
+ if (regionp)
+ {
+ BOOL was_flying = gAgent.getFlying();
+ regionp->setRegionFlags(region_flags);
+ regionp->setMaxTasks(max_tasks_per_region);
+ // HACK: This makes agents drop from the sky if the region is
+ // set to no fly while people are still in the sim.
+ if (was_flying && regionp->getBlockFly())
+ {
+ gAgent.setFlying(gAgent.canFly());
+ }
+ }
+}
+
+
+
+void process_avatar_animation(LLMessageSystem *mesgsys, void **user_data)
+{
+ LLUUID animation_id;
+ LLUUID uuid;
+ S32 anim_sequence_id;
+ LLVOAvatar *avatarp;
+
+ mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid);
+
+ //clear animation flags
+ avatarp = (LLVOAvatar *)gObjectList.findObject(uuid);
+
+ if (!avatarp)
+ {
+ // no agent by this ID...error?
+ LL_WARNS("Messaging") << "Received animation state for unknown avatar" << uuid << LL_ENDL;
+ return;
+ }
+
+ S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationList);
+ S32 num_source_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_AnimationSourceList);
+
+ avatarp->mSignaledAnimations.clear();
+
+ if (avatarp->isSelf())
+ {
+ LLUUID object_id;
+
+ for( S32 i = 0; i < num_blocks; i++ )
+ {
+ mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i);
+ mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i);
+
+ LL_DEBUGS("Messaging") << "Anim sequence ID: " << anim_sequence_id << LL_ENDL;
+
+ avatarp->mSignaledAnimations[animation_id] = anim_sequence_id;
+
+ // *HACK: Disabling flying mode if it has been enabled shortly before the agent
+ // stand up animation is signaled. In this case we don't get a signal to start
+ // flying animation from server, the AGENT_CONTROL_FLY flag remains set but the
+ // avatar does not play flying animation, so we switch flying mode off.
+ // See LLAgent::setFlying(). This may cause "Stop Flying" button to blink.
+ // See EXT-2781.
+ if (animation_id == ANIM_AGENT_STANDUP && gAgent.getFlying())
+ {
+ gAgent.setFlying(FALSE);
+ }
+
+ if (i < num_source_blocks)
+ {
+ mesgsys->getUUIDFast(_PREHASH_AnimationSourceList, _PREHASH_ObjectID, object_id, i);
+
+ LLViewerObject* object = gObjectList.findObject(object_id);
+ if (object)
+ {
+ object->mFlags |= FLAGS_ANIM_SOURCE;
+
+ BOOL anim_found = FALSE;
+ LLVOAvatar::AnimSourceIterator anim_it = avatarp->mAnimationSources.find(object_id);
+ for (;anim_it != avatarp->mAnimationSources.end(); ++anim_it)
+ {
+ if (anim_it->second == animation_id)
+ {
+ anim_found = TRUE;
+ break;
+ }
+ }
+
+ if (!anim_found)
+ {
+ avatarp->mAnimationSources.insert(LLVOAvatar::AnimationSourceMap::value_type(object_id, animation_id));
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ for( S32 i = 0; i < num_blocks; i++ )
+ {
+ mesgsys->getUUIDFast(_PREHASH_AnimationList, _PREHASH_AnimID, animation_id, i);
+ mesgsys->getS32Fast(_PREHASH_AnimationList, _PREHASH_AnimSequenceID, anim_sequence_id, i);
+ avatarp->mSignaledAnimations[animation_id] = anim_sequence_id;
+ }
+ }
+
+ if (num_blocks)
+ {
+ avatarp->processAnimationStateChanges();
+ }
+}
+
+void process_avatar_appearance(LLMessageSystem *mesgsys, void **user_data)
+{
+ LLUUID uuid;
+ mesgsys->getUUIDFast(_PREHASH_Sender, _PREHASH_ID, uuid);
+
+ LLVOAvatar* avatarp = (LLVOAvatar *)gObjectList.findObject(uuid);
+ if (avatarp)
+ {
+ avatarp->processAvatarAppearance( mesgsys );
+ }
+ else
+ {
+ LL_WARNS("Messaging") << "avatar_appearance sent for unknown avatar " << uuid << LL_ENDL;
+ }
+}
+
+void process_camera_constraint(LLMessageSystem *mesgsys, void **user_data)
+{
+ LLVector4 cameraCollidePlane;
+ mesgsys->getVector4Fast(_PREHASH_CameraCollidePlane, _PREHASH_Plane, cameraCollidePlane);
+
+ gAgentCamera.setCameraCollidePlane(cameraCollidePlane);
+}
+
+void near_sit_object(BOOL success, void *data)
+{
+ if (success)
+ {
+ // Send message to sit on object
+ gMessageSystem->newMessageFast(_PREHASH_AgentSit);
+ gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+ gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ gAgent.sendReliableMessage();
+ }
+}
+
+void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data)
+{
+ LLVector3 sitPosition;
+ LLQuaternion sitRotation;
+ LLUUID sitObjectID;
+ BOOL use_autopilot;
+ mesgsys->getUUIDFast(_PREHASH_SitObject, _PREHASH_ID, sitObjectID);
+ mesgsys->getBOOLFast(_PREHASH_SitTransform, _PREHASH_AutoPilot, use_autopilot);
+ mesgsys->getVector3Fast(_PREHASH_SitTransform, _PREHASH_SitPosition, sitPosition);
+ mesgsys->getQuatFast(_PREHASH_SitTransform, _PREHASH_SitRotation, sitRotation);
+ LLVector3 camera_eye;
+ mesgsys->getVector3Fast(_PREHASH_SitTransform, _PREHASH_CameraEyeOffset, camera_eye);
+ LLVector3 camera_at;
+ mesgsys->getVector3Fast(_PREHASH_SitTransform, _PREHASH_CameraAtOffset, camera_at);
+ BOOL force_mouselook;
+ mesgsys->getBOOLFast(_PREHASH_SitTransform, _PREHASH_ForceMouselook, force_mouselook);
+
+ if (isAgentAvatarValid() && dist_vec_squared(camera_eye, camera_at) > 0.0001f)
+ {
+ gAgentCamera.setSitCamera(sitObjectID, camera_eye, camera_at);
+ }
+
+ gAgentCamera.setForceMouselook(force_mouselook);
+ // Forcing turning off flying here to prevent flying after pressing "Stand"
+ // to stand up from an object. See EXT-1655.
+ gAgent.setFlying(FALSE);
+
+ LLViewerObject* object = gObjectList.findObject(sitObjectID);
+ if (object)
+ {
+ LLVector3 sit_spot = object->getPositionAgent() + (sitPosition * object->getRotation());
+ if (!use_autopilot || isAgentAvatarValid() && gAgentAvatarp->isSitting() && gAgentAvatarp->getRoot() == object->getRoot())
+ {
+ //we're already sitting on this object, so don't autopilot
+ }
+ else
+ {
+ gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(sit_spot), "Sit", &sitRotation, near_sit_object, NULL, 0.5f);
+ }
+ }
+ else
+ {
+ LL_WARNS("Messaging") << "Received sit approval for unknown object " << sitObjectID << LL_ENDL;
+ }
+}
+
+void process_clear_follow_cam_properties(LLMessageSystem *mesgsys, void **user_data)
+{
+ LLUUID source_id;
+
+ mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, source_id);
+
+ LLFollowCamMgr::removeFollowCamParams(source_id);
+}
+
+void process_set_follow_cam_properties(LLMessageSystem *mesgsys, void **user_data)
+{
+ S32 type;
+ F32 value;
+ bool settingPosition = false;
+ bool settingFocus = false;
+ bool settingFocusOffset = false;
+ LLVector3 position;
+ LLVector3 focus;
+ LLVector3 focus_offset;
+
+ LLUUID source_id;
+
+ mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_ObjectID, source_id);
+
+ LLViewerObject* objectp = gObjectList.findObject(source_id);
+ if (objectp)
+ {
+ objectp->mFlags |= FLAGS_CAMERA_SOURCE;
+ }
+
+ S32 num_objects = mesgsys->getNumberOfBlocks("CameraProperty");
+ for (S32 block_index = 0; block_index < num_objects; block_index++)
+ {
+ mesgsys->getS32("CameraProperty", "Type", type, block_index);
+ mesgsys->getF32("CameraProperty", "Value", value, block_index);
+ switch(type)
+ {
+ case FOLLOWCAM_PITCH:
+ LLFollowCamMgr::setPitch(source_id, value);
+ break;
+ case FOLLOWCAM_FOCUS_OFFSET_X:
+ focus_offset.mV[VX] = value;
+ settingFocusOffset = true;
+ break;
+ case FOLLOWCAM_FOCUS_OFFSET_Y:
+ focus_offset.mV[VY] = value;
+ settingFocusOffset = true;
+ break;
+ case FOLLOWCAM_FOCUS_OFFSET_Z:
+ focus_offset.mV[VZ] = value;
+ settingFocusOffset = true;
+ break;
+ case FOLLOWCAM_POSITION_LAG:
+ LLFollowCamMgr::setPositionLag(source_id, value);
+ break;
+ case FOLLOWCAM_FOCUS_LAG:
+ LLFollowCamMgr::setFocusLag(source_id, value);
+ break;
+ case FOLLOWCAM_DISTANCE:
+ LLFollowCamMgr::setDistance(source_id, value);
+ break;
+ case FOLLOWCAM_BEHINDNESS_ANGLE:
+ LLFollowCamMgr::setBehindnessAngle(source_id, value);
+ break;
+ case FOLLOWCAM_BEHINDNESS_LAG:
+ LLFollowCamMgr::setBehindnessLag(source_id, value);
+ break;
+ case FOLLOWCAM_POSITION_THRESHOLD:
+ LLFollowCamMgr::setPositionThreshold(source_id, value);
+ break;
+ case FOLLOWCAM_FOCUS_THRESHOLD:
+ LLFollowCamMgr::setFocusThreshold(source_id, value);
+ break;
+ case FOLLOWCAM_ACTIVE:
+ //if 1, set using followcam,.
+ LLFollowCamMgr::setCameraActive(source_id, value != 0.f);
+ break;
+ case FOLLOWCAM_POSITION_X:
+ settingPosition = true;
+ position.mV[ 0 ] = value;
+ break;
+ case FOLLOWCAM_POSITION_Y:
+ settingPosition = true;
+ position.mV[ 1 ] = value;
+ break;
+ case FOLLOWCAM_POSITION_Z:
+ settingPosition = true;
+ position.mV[ 2 ] = value;
+ break;
+ case FOLLOWCAM_FOCUS_X:
+ settingFocus = true;
+ focus.mV[ 0 ] = value;
+ break;
+ case FOLLOWCAM_FOCUS_Y:
+ settingFocus = true;
+ focus.mV[ 1 ] = value;
+ break;
+ case FOLLOWCAM_FOCUS_Z:
+ settingFocus = true;
+ focus.mV[ 2 ] = value;
+ break;
+ case FOLLOWCAM_POSITION_LOCKED:
+ LLFollowCamMgr::setPositionLocked(source_id, value != 0.f);
+ break;
+ case FOLLOWCAM_FOCUS_LOCKED:
+ LLFollowCamMgr::setFocusLocked(source_id, value != 0.f);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if ( settingPosition )
+ {
+ LLFollowCamMgr::setPosition(source_id, position);
+ }
+ if ( settingFocus )
+ {
+ LLFollowCamMgr::setFocus(source_id, focus);
+ }
+ if ( settingFocusOffset )
+ {
+ LLFollowCamMgr::setFocusOffset(source_id, focus_offset);
+ }
+}
+//end Ventrella
+
+
+// Culled from newsim lltask.cpp
+void process_name_value(LLMessageSystem *mesgsys, void **user_data)
+{
+ std::string temp_str;
+ LLUUID id;
+ S32 i, num_blocks;
+
+ mesgsys->getUUIDFast(_PREHASH_TaskData, _PREHASH_ID, id);
+
+ LLViewerObject* object = gObjectList.findObject(id);
+
+ if (object)
+ {
+ num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_NameValueData);
+ for (i = 0; i < num_blocks; i++)
+ {
+ mesgsys->getStringFast(_PREHASH_NameValueData, _PREHASH_NVPair, temp_str, i);
+ LL_INFOS("Messaging") << "Added to object Name Value: " << temp_str << LL_ENDL;
+ object->addNVPair(temp_str);
+ }
+ }
+ else
+ {
+ LL_INFOS("Messaging") << "Can't find object " << id << " to add name value pair" << LL_ENDL;
+ }
+}
+
+void process_remove_name_value(LLMessageSystem *mesgsys, void **user_data)
+{
+ std::string temp_str;
+ LLUUID id;
+ S32 i, num_blocks;
+
+ mesgsys->getUUIDFast(_PREHASH_TaskData, _PREHASH_ID, id);
+
+ LLViewerObject* object = gObjectList.findObject(id);
+
+ if (object)
+ {
+ num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_NameValueData);
+ for (i = 0; i < num_blocks; i++)
+ {
+ mesgsys->getStringFast(_PREHASH_NameValueData, _PREHASH_NVPair, temp_str, i);
+ LL_INFOS("Messaging") << "Removed from object Name Value: " << temp_str << LL_ENDL;
+ object->removeNVPair(temp_str);
+ }
+ }
+ else
+ {
+ LL_INFOS("Messaging") << "Can't find object " << id << " to remove name value pair" << LL_ENDL;
+ }
+}
+
+void process_kick_user(LLMessageSystem *msg, void** /*user_data*/)
+{
+ std::string message;
+
+ msg->getStringFast(_PREHASH_UserInfo, _PREHASH_Reason, message);
+
+ LLAppViewer::instance()->forceDisconnect(message);
+}
+
+
+/*
+void process_user_list_reply(LLMessageSystem *msg, void **user_data)
+{
+ LLUserList::processUserListReply(msg, user_data);
+ return;
+ char firstname[MAX_STRING+1];
+ char lastname[MAX_STRING+1];
+ U8 status;
+ S32 user_count;
+
+ user_count = msg->getNumberOfBlocks("UserBlock");
+
+ for (S32 i = 0; i < user_count; i++)
+ {
+ msg->getData("UserBlock", i, "FirstName", firstname);
+ msg->getData("UserBlock", i, "LastName", lastname);
+ msg->getData("UserBlock", i, "Status", &status);
+
+ if (status & 0x01)
+ {
+ dialog_friends_add_friend(buffer, TRUE);
+ }
+ else
+ {
+ dialog_friends_add_friend(buffer, FALSE);
+ }
+ }
+
+ dialog_friends_done_adding();
+}
+*/
+
+// this is not handled in processUpdateMessage
+/*
+void process_time_dilation(LLMessageSystem *msg, void **user_data)
+{
+ // get the time_dilation
+ U16 foo;
+ msg->getData("TimeDilation", "TimeDilation", &foo);
+ F32 time_dilation = ((F32) foo) / 65535.f;
+
+ // get the pointer to the right region
+ U32 ip = msg->getSenderIP();
+ U32 port = msg->getSenderPort();
+ LLViewerRegion *regionp = LLWorld::getInstance()->getRegion(ip, port);
+ if (regionp)
+ {
+ regionp->setTimeDilation(time_dilation);
+ }
+}
+*/
+
+
+void process_money_balance_reply( LLMessageSystem* msg, void** )
+{
+ S32 balance = 0;
+ S32 credit = 0;
+ S32 committed = 0;
+ std::string desc;
+ LLUUID tid;
+
+ msg->getUUID("MoneyData", "TransactionID", tid);
+ msg->getS32("MoneyData", "MoneyBalance", balance);
+ msg->getS32("MoneyData", "SquareMetersCredit", credit);
+ msg->getS32("MoneyData", "SquareMetersCommitted", committed);
+ msg->getStringFast(_PREHASH_MoneyData, _PREHASH_Description, desc);
+ LL_INFOS("Messaging") << "L$, credit, committed: " << balance << " " << credit << " "
+ << committed << LL_ENDL;
+
+ if (gStatusBar)
+ {
+ gStatusBar->setBalance(balance);
+ gStatusBar->setLandCredit(credit);
+ gStatusBar->setLandCommitted(committed);
+ }
+
+ if (desc.empty()
+ || !gSavedSettings.getBOOL("NotifyMoneyChange"))
+ {
+ // ...nothing to display
+ return;
+ }
+
+ // Suppress duplicate messages about the same transaction
+ static std::deque<LLUUID> recent;
+ if (std::find(recent.rbegin(), recent.rend(), tid) != recent.rend())
+ {
+ return;
+ }
+
+ // Once the 'recent' container gets large enough, chop some
+ // off the beginning.
+ const U32 MAX_LOOKBACK = 30;
+ const S32 POP_FRONT_SIZE = 12;
+ if(recent.size() > MAX_LOOKBACK)
+ {
+ LL_DEBUGS("Messaging") << "Removing oldest transaction records" << LL_ENDL;
+ recent.erase(recent.begin(), recent.begin() + POP_FRONT_SIZE);
+ }
+ //LL_DEBUGS("Messaging") << "Pushing back transaction " << tid << LL_ENDL;
+ recent.push_back(tid);
+
+ if (msg->has("TransactionInfo"))
+ {
+ // ...message has extended info for localization
+ process_money_balance_reply_extended(msg);
+ }
+ else
+ {
+ // Only old dev grids will not supply the TransactionInfo block,
+ // so we can just use the hard-coded English string.
+ LLSD args;
+ args["MESSAGE"] = desc;
+ LLNotificationsUtil::add("SystemMessage", args);
+ }
+}
+
+static std::string reason_from_transaction_type(S32 transaction_type,
+ const std::string& item_desc)
+{
+ // *NOTE: The keys for the reason strings are unusual because
+ // an earlier version of the code used English language strings
+ // extracted from hard-coded server English descriptions.
+ // Keeping them so we don't have to re-localize them.
+ switch (transaction_type)
+ {
+ case TRANS_OBJECT_SALE:
+ {
+ LLStringUtil::format_map_t arg;
+ arg["ITEM"] = item_desc;
+ return LLTrans::getString("for item", arg);
+ }
+ case TRANS_LAND_SALE:
+ return LLTrans::getString("for a parcel of land");
+
+ case TRANS_LAND_PASS_SALE:
+ return LLTrans::getString("for a land access pass");
+
+ case TRANS_GROUP_LAND_DEED:
+ return LLTrans::getString("for deeding land");
+
+ case TRANS_GROUP_CREATE:
+ return LLTrans::getString("to create a group");
+
+ case TRANS_GROUP_JOIN:
+ return LLTrans::getString("to join a group");
+
+ case TRANS_UPLOAD_CHARGE:
+ return LLTrans::getString("to upload");
+
+ case TRANS_CLASSIFIED_CHARGE:
+ return LLTrans::getString("to publish a classified ad");
+
+ // These have no reason to display, but are expected and should not
+ // generate warnings
+ case TRANS_GIFT:
+ case TRANS_PAY_OBJECT:
+ case TRANS_OBJECT_PAYS:
+ return std::string();
+
+ default:
+ llwarns << "Unknown transaction type "
+ << transaction_type << llendl;
+ return std::string();
+ }
+}
+
+static void money_balance_group_notify(const LLUUID& group_id,
+ const std::string& name,
+ bool is_group,
+ std::string notification,
+ LLSD args,
+ LLSD payload)
+{
+ // Message uses name SLURLs, don't actually have to substitute in
+ // the name. We're just making sure it's available.
+ // Notification is either PaymentReceived or PaymentSent
+ LLNotificationsUtil::add(notification, args, payload);
+}
+
+static void money_balance_avatar_notify(const LLUUID& agent_id,
+ const LLAvatarName& av_name,
+ std::string notification,
+ LLSD args,
+ LLSD payload)
+{
+ // Message uses name SLURLs, don't actually have to substitute in
+ // the name. We're just making sure it's available.
+ // Notification is either PaymentReceived or PaymentSent
+ LLNotificationsUtil::add(notification, args, payload);
+}
+
+static void process_money_balance_reply_extended(LLMessageSystem* msg)
+{
+ // Added in server 1.40 and viewer 2.1, support for localization
+ // and agent ids for name lookup.
+ S32 transaction_type = 0;
+ LLUUID source_id;
+ BOOL is_source_group = FALSE;
+ LLUUID dest_id;
+ BOOL is_dest_group = FALSE;
+ S32 amount = 0;
+ std::string item_description;
+
+ msg->getS32("TransactionInfo", "TransactionType", transaction_type);
+ msg->getUUID("TransactionInfo", "SourceID", source_id);
+ msg->getBOOL("TransactionInfo", "IsSourceGroup", is_source_group);
+ msg->getUUID("TransactionInfo", "DestID", dest_id);
+ msg->getBOOL("TransactionInfo", "IsDestGroup", is_dest_group);
+ msg->getS32("TransactionInfo", "Amount", amount);
+ msg->getString("TransactionInfo", "ItemDescription", item_description);
+ LL_INFOS("Money") << "MoneyBalanceReply source " << source_id
+ << " dest " << dest_id
+ << " type " << transaction_type
+ << " item " << item_description << LL_ENDL;
+
+ if (source_id.isNull() && dest_id.isNull())
+ {
+ // this is a pure balance update, no notification required
+ return;
+ }
+
+ std::string source_slurl;
+ if (is_source_group)
+ {
+ source_slurl =
+ LLSLURL( "group", source_id, "inspect").getSLURLString();
+ }
+ else
+ {
+ source_slurl =
+ LLSLURL( "agent", source_id, "completename").getSLURLString();
+ }
+
+ std::string dest_slurl;
+ if (is_dest_group)
+ {
+ dest_slurl =
+ LLSLURL( "group", dest_id, "inspect").getSLURLString();
+ }
+ else
+ {
+ dest_slurl =
+ LLSLURL( "agent", dest_id, "completename").getSLURLString();
+ }
+
+ std::string reason =
+ reason_from_transaction_type(transaction_type, item_description);
+
+ LLStringUtil::format_map_t args;
+ args["REASON"] = reason; // could be empty
+ args["AMOUNT"] = llformat("%d", amount);
+
+ // Need to delay until name looked up, so need to know whether or not
+ // is group
+ bool is_name_group = false;
+ LLUUID name_id;
+ std::string message;
+ std::string notification;
+ LLSD final_args;
+ LLSD payload;
+
+ bool you_paid_someone = (source_id == gAgentID);
+ if (you_paid_someone)
+ {
+ args["NAME"] = dest_slurl;
+ is_name_group = is_dest_group;
+ name_id = dest_id;
+ if (!reason.empty())
+ {
+ if (dest_id.notNull())
+ {
+ message = LLTrans::getString("you_paid_ldollars", args);
+ }
+ else
+ {
+ // transaction fee to the system, eg, to create a group
+ message = LLTrans::getString("you_paid_ldollars_no_name", args);
+ }
+ }
+ else
+ {
+ if (dest_id.notNull())
+ {
+ message = LLTrans::getString("you_paid_ldollars_no_reason", args);
+ }
+ else
+ {
+ // no target, no reason, you just paid money
+ message = LLTrans::getString("you_paid_ldollars_no_info", args);
+ }
+ }
+ final_args["MESSAGE"] = message;
+ notification = "PaymentSent";
+ }
+ else {
+ // ...someone paid you
+ args["NAME"] = source_slurl;
+ is_name_group = is_source_group;
+ name_id = source_id;
+ if (!reason.empty())
+ {
+ message = LLTrans::getString("paid_you_ldollars", args);
+ }
+ else {
+ message = LLTrans::getString("paid_you_ldollars_no_reason", args);
+ }
+ final_args["MESSAGE"] = message;
+
+ // make notification loggable
+ payload["from_id"] = source_id;
+ notification = "PaymentReceived";
+ }
+
+ // Despite using SLURLs, wait until the name is available before
+ // showing the notification, otherwise the UI layout is strange and
+ // the user sees a "Loading..." message
+ if (is_name_group)
+ {
+ gCacheName->getGroup(name_id,
+ boost::bind(&money_balance_group_notify,
+ _1, _2, _3,
+ notification, final_args, payload));
+ }
+ else {
+ LLAvatarNameCache::get(name_id,
+ boost::bind(&money_balance_avatar_notify,
+ _1, _2,
+ notification, final_args, payload));
+ }
+}
+
+
+
+bool handle_special_notification_callback(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+
+ if (0 == option)
+ {
+ // set the preference to the maturity of the region we're calling
+ int preferredMaturity = notification["payload"]["_region_access"].asInteger();
+ gSavedSettings.setU32("PreferredMaturity", preferredMaturity);
+ gAgent.sendMaturityPreferenceToServer(preferredMaturity);
+
+ // notify user that the maturity preference has been changed
+ LLSD args;
+ args["RATING"] = LLViewerRegion::accessToString(preferredMaturity);
+ LLNotificationsUtil::add("PreferredMaturityChanged", args);
+ }
+
+ return false;
+}
+
+// some of the server notifications need special handling. This is where we do that.
+bool handle_special_notification(std::string notificationID, LLSD& llsdBlock)
+{
+ int regionAccess = llsdBlock["_region_access"].asInteger();
+ llsdBlock["REGIONMATURITY"] = LLViewerRegion::accessToString(regionAccess);
+
+ // we're going to throw the LLSD in there in case anyone ever wants to use it
+ LLNotificationsUtil::add(notificationID+"_Notify", llsdBlock);
+
+ if (regionAccess == SIM_ACCESS_MATURE)
+ {
+ if (gAgent.isTeen())
+ {
+ LLNotificationsUtil::add(notificationID+"_KB", llsdBlock);
+ return true;
+ }
+ else if (gAgent.prefersPG())
+ {
+ LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_special_notification_callback);
+ return true;
+ }
+ }
+ else if (regionAccess == SIM_ACCESS_ADULT)
+ {
+ if (!gAgent.isAdult())
+ {
+ LLNotificationsUtil::add(notificationID+"_KB", llsdBlock);
+ return true;
+ }
+ else if (gAgent.prefersPG() || gAgent.prefersMature())
+ {
+ LLNotificationsUtil::add(notificationID+"_Change", llsdBlock, llsdBlock, handle_special_notification_callback);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool attempt_standard_notification(LLMessageSystem* msgsystem)
+{
+ // if we have additional alert data
+ if (msgsystem->has(_PREHASH_AlertInfo) && msgsystem->getNumberOfBlocksFast(_PREHASH_AlertInfo) > 0)
+ {
+ // notification was specified using the new mechanism, so we can just handle it here
+ std::string notificationID;
+ std::string llsdRaw;
+ LLSD llsdBlock;
+ msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, notificationID);
+ msgsystem->getStringFast(_PREHASH_AlertInfo, _PREHASH_ExtraParams, llsdRaw);
+ if (llsdRaw.length())
+ {
+ std::istringstream llsdData(llsdRaw);
+ if (!LLSDSerialize::deserialize(llsdBlock, llsdData, llsdRaw.length()))
+ {
+ llwarns << "attempt_standard_notification: Attempted to read notification parameter data into LLSD but failed:" << llsdRaw << llendl;
+ }
+ }
+
+ if (
+ (notificationID == "RegionEntryAccessBlocked") ||
+ (notificationID == "LandClaimAccessBlocked") ||
+ (notificationID == "LandBuyAccessBlocked")
+ )
+ {
+ /*---------------------------------------------------------------------
+ (Commented so a grep will find the notification strings, since
+ we construct them on the fly; if you add additional notifications,
+ please update the comment.)
+
+ Could throw any of the following notifications:
+
+ RegionEntryAccessBlocked
+ RegionEntryAccessBlocked_Notify
+ RegionEntryAccessBlocked_Change
+ RegionEntryAccessBlocked_KB
+ LandClaimAccessBlocked
+ LandClaimAccessBlocked_Notify
+ LandClaimAccessBlocked_Change
+ LandClaimAccessBlocked_KB
+ LandBuyAccessBlocked
+ LandBuyAccessBlocked_Notify
+ LandBuyAccessBlocked_Change
+ LandBuyAccessBlocked_KB
+
+ -----------------------------------------------------------------------*/
+ if (handle_special_notification(notificationID, llsdBlock))
+ {
+ return true;
+ }
+ }
+
+ LLNotificationsUtil::add(notificationID, llsdBlock);
+ return true;
+ }
+ return false;
+}
+
+
+void process_agent_alert_message(LLMessageSystem* msgsystem, void** user_data)
+{
+ // make sure the cursor is back to the usual default since the
+ // alert is probably due to some kind of error.
+ gViewerWindow->getWindow()->resetBusyCount();
+
+ if (!attempt_standard_notification(msgsystem))
+ {
+ BOOL modal = FALSE;
+ msgsystem->getBOOL("AlertData", "Modal", modal);
+ std::string buffer;
+ msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, buffer);
+ process_alert_core(buffer, modal);
+ }
+}
+
+// The only difference between this routine and the previous is the fact that
+// for this routine, the modal parameter is always false. Sadly, for the message
+// handled by this routine, there is no "Modal" parameter on the message, and
+// there's no API to tell if a message has the given parameter or not.
+// So we can't handle the messages with the same handler.
+void process_alert_message(LLMessageSystem *msgsystem, void **user_data)
+{
+ // make sure the cursor is back to the usual default since the
+ // alert is probably due to some kind of error.
+ gViewerWindow->getWindow()->resetBusyCount();
+
+ if (!attempt_standard_notification(msgsystem))
+ {
+ BOOL modal = FALSE;
+ std::string buffer;
+ msgsystem->getStringFast(_PREHASH_AlertData, _PREHASH_Message, buffer);
+ process_alert_core(buffer, modal);
+ }
+}
+
+void process_alert_core(const std::string& message, BOOL modal)
+{
+ // HACK -- handle callbacks for specific alerts. It also is localized in notifications.xml
+ if ( message == "You died and have been teleported to your home location")
+ {
+ LLViewerStats::getInstance()->incStat(LLViewerStats::ST_KILLED_COUNT);
+ }
+ else if( message == "Home position set." )
+ {
+ // save the home location image to disk
+ std::string snap_filename = gDirUtilp->getLindenUserDir();
+ snap_filename += gDirUtilp->getDirDelimiter();
+ snap_filename += SCREEN_HOME_FILENAME;
+ gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw(), FALSE, FALSE);
+ }
+
+ const std::string ALERT_PREFIX("ALERT: ");
+ const std::string NOTIFY_PREFIX("NOTIFY: ");
+ if (message.find(ALERT_PREFIX) == 0)
+ {
+ // Allow the server to spawn a named alert so that server alerts can be
+ // translated out of English.
+ std::string alert_name(message.substr(ALERT_PREFIX.length()));
+ LLNotificationsUtil::add(alert_name);
+ }
+ else if (message.find(NOTIFY_PREFIX) == 0)
+ {
+ // Allow the server to spawn a named notification so that server notifications can be
+ // translated out of English.
+ std::string notify_name(message.substr(NOTIFY_PREFIX.length()));
+ LLNotificationsUtil::add(notify_name);
+ }
+ else if (message[0] == '/')
+ {
+ // System message is important, show in upper-right box not tip
+ std::string text(message.substr(1));
+ LLSD args;
+ if (text.substr(0,17) == "RESTART_X_MINUTES")
+ {
+ S32 mins = 0;
+ LLStringUtil::convertToS32(text.substr(18), mins);
+ args["MINUTES"] = llformat("%d",mins);
+ LLNotificationsUtil::add("RegionRestartMinutes", args);
+ }
+ else if (text.substr(0,17) == "RESTART_X_SECONDS")
+ {
+ S32 secs = 0;
+ LLStringUtil::convertToS32(text.substr(18), secs);
+ args["SECONDS"] = llformat("%d",secs);
+ LLNotificationsUtil::add("RegionRestartSeconds", args);
+ }
+ else
+ {
+ std::string new_msg =LLNotifications::instance().getGlobalString(text);
+ args["MESSAGE"] = new_msg;
+ LLNotificationsUtil::add("SystemMessage", args);
+ }
+ }
+ else if (modal)
+ {
+ LLSD args;
+ std::string new_msg =LLNotifications::instance().getGlobalString(message);
+ args["ERROR_MESSAGE"] = new_msg;
+ LLNotificationsUtil::add("ErrorMessage", args);
+ }
+ else
+ {
+ LLSD args;
+ std::string new_msg =LLNotifications::instance().getGlobalString(message);
+ args["MESSAGE"] = new_msg;
+ LLNotificationsUtil::add("SystemMessageTip", args);
+ }
+}
+
+mean_collision_list_t gMeanCollisionList;
+time_t gLastDisplayedTime = 0;
+
+void handle_show_mean_events(void *)
+{
+ if (gNoRender)
+ {
+ return;
+ }
+ LLFloaterReg::showInstance("bumps");
+ //LLFloaterBump::showInstance();
+}
+
+void mean_name_callback(const LLUUID &id, const std::string& full_name, bool is_group)
+{
+ if (gNoRender)
+ {
+ return;
+ }
+
+ static const U32 max_collision_list_size = 20;
+ if (gMeanCollisionList.size() > max_collision_list_size)
+ {
+ mean_collision_list_t::iterator iter = gMeanCollisionList.begin();
+ for (U32 i=0; i<max_collision_list_size; i++) iter++;
+ for_each(iter, gMeanCollisionList.end(), DeletePointer());
+ gMeanCollisionList.erase(iter, gMeanCollisionList.end());
+ }
+
+ for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin();
+ iter != gMeanCollisionList.end(); ++iter)
+ {
+ LLMeanCollisionData *mcd = *iter;
+ if (mcd->mPerp == id)
+ {
+ mcd->mFullName = full_name;
+ }
+ }
+}
+
+void process_mean_collision_alert_message(LLMessageSystem *msgsystem, void **user_data)
+{
+ if (gAgent.inPrelude())
+ {
+ // In prelude, bumping is OK. This dialog is rather confusing to
+ // newbies, so we don't show it. Drop the packet on the floor.
+ return;
+ }
+
+ // make sure the cursor is back to the usual default since the
+ // alert is probably due to some kind of error.
+ gViewerWindow->getWindow()->resetBusyCount();
+
+ LLUUID perp;
+ U32 time;
+ U8 u8type;
+ EMeanCollisionType type;
+ F32 mag;
+
+ S32 i, num = msgsystem->getNumberOfBlocks(_PREHASH_MeanCollision);
+
+ for (i = 0; i < num; i++)
+ {
+ msgsystem->getUUIDFast(_PREHASH_MeanCollision, _PREHASH_Perp, perp);
+ msgsystem->getU32Fast(_PREHASH_MeanCollision, _PREHASH_Time, time);
+ msgsystem->getF32Fast(_PREHASH_MeanCollision, _PREHASH_Mag, mag);
+ msgsystem->getU8Fast(_PREHASH_MeanCollision, _PREHASH_Type, u8type);
+
+ type = (EMeanCollisionType)u8type;
+
+ BOOL b_found = FALSE;
+
+ for (mean_collision_list_t::iterator iter = gMeanCollisionList.begin();
+ iter != gMeanCollisionList.end(); ++iter)
+ {
+ LLMeanCollisionData *mcd = *iter;
+ if ((mcd->mPerp == perp) && (mcd->mType == type))
+ {
+ mcd->mTime = time;
+ mcd->mMag = mag;
+ b_found = TRUE;
+ break;
+ }
+ }
+
+ if (!b_found)
+ {
+ LLMeanCollisionData *mcd = new LLMeanCollisionData(gAgentID, perp, time, type, mag);
+ gMeanCollisionList.push_front(mcd);
+ gCacheName->get(perp, false, boost::bind(&mean_name_callback, _1, _2, _3));
+ }
+ }
+}
+
+void process_frozen_message(LLMessageSystem *msgsystem, void **user_data)
+{
+ // make sure the cursor is back to the usual default since the
+ // alert is probably due to some kind of error.
+ gViewerWindow->getWindow()->resetBusyCount();
+ BOOL b_frozen;
+
+ msgsystem->getBOOL("FrozenData", "Data", b_frozen);
+
+ // TODO: make being frozen change view
+ if (b_frozen)
+ {
+ }
+ else
+ {
+ }
+}
+
+// do some extra stuff once we get our economy data
+void process_economy_data(LLMessageSystem *msg, void** /*user_data*/)
+{
+ LLGlobalEconomy::processEconomyData(msg, LLGlobalEconomy::Singleton::getInstance());
+
+ S32 upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
+
+ LL_INFOS_ONCE("Messaging") << "EconomyData message arrived; upload cost is L$" << upload_cost << LL_ENDL;
+
+ gMenuHolder->getChild<LLUICtrl>("Upload Image")->setLabelArg("[COST]", llformat("%d", upload_cost));
+ gMenuHolder->getChild<LLUICtrl>("Upload Sound")->setLabelArg("[COST]", llformat("%d", upload_cost));
+ gMenuHolder->getChild<LLUICtrl>("Upload Animation")->setLabelArg("[COST]", llformat("%d", upload_cost));
+ gMenuHolder->getChild<LLUICtrl>("Bulk Upload")->setLabelArg("[COST]", llformat("%d", upload_cost));
+}
+
+void notify_cautioned_script_question(const LLSD& notification, const LLSD& response, S32 orig_questions, BOOL granted)
+{
+ // only continue if at least some permissions were requested
+ if (orig_questions)
+ {
+ // check to see if the person we are asking
+
+ // "'[OBJECTNAME]', an object owned by '[OWNERNAME]',
+ // located in [REGIONNAME] at [REGIONPOS],
+ // has been <granted|denied> permission to: [PERMISSIONS]."
+
+ LLUIString notice(LLTrans::getString(granted ? "ScriptQuestionCautionChatGranted" : "ScriptQuestionCautionChatDenied"));
+
+ // always include the object name and owner name
+ notice.setArg("[OBJECTNAME]", notification["payload"]["object_name"].asString());
+ notice.setArg("[OWNERNAME]", notification["payload"]["owner_name"].asString());
+
+ // try to lookup viewerobject that corresponds to the object that
+ // requested permissions (here, taskid->requesting object id)
+ BOOL foundpos = FALSE;
+ LLViewerObject* viewobj = gObjectList.findObject(notification["payload"]["task_id"].asUUID());
+ if (viewobj)
+ {
+ // found the viewerobject, get it's position in its region
+ LLVector3 objpos(viewobj->getPosition());
+
+ // try to lookup the name of the region the object is in
+ LLViewerRegion* viewregion = viewobj->getRegion();
+ if (viewregion)
+ {
+ // got the region, so include the region and 3d coordinates of the object
+ notice.setArg("[REGIONNAME]", viewregion->getName());
+ std::string formatpos = llformat("%.1f, %.1f,%.1f", objpos[VX], objpos[VY], objpos[VZ]);
+ notice.setArg("[REGIONPOS]", formatpos);
+
+ foundpos = TRUE;
+ }
+ }
+
+ if (!foundpos)
+ {
+ // unable to determine location of the object
+ notice.setArg("[REGIONNAME]", "(unknown region)");
+ notice.setArg("[REGIONPOS]", "(unknown position)");
+ }
+
+ // check each permission that was requested, and list each
+ // permission that has been flagged as a caution permission
+ BOOL caution = FALSE;
+ S32 count = 0;
+ std::string perms;
+ for (S32 i = 0; i < SCRIPT_PERMISSION_EOF; i++)
+ {
+ if ((orig_questions & LSCRIPTRunTimePermissionBits[i]) && SCRIPT_QUESTION_IS_CAUTION[i])
+ {
+ count++;
+ caution = TRUE;
+
+ // add a comma before the permission description if it is not the first permission
+ // added to the list or the last permission to check
+ if ((count > 1) && (i < SCRIPT_PERMISSION_EOF))
+ {
+ perms.append(", ");
+ }
+
+ perms.append(LLTrans::getString(SCRIPT_QUESTIONS[i]));
+ }
+ }
+
+ notice.setArg("[PERMISSIONS]", perms);
+
+ // log a chat message as long as at least one requested permission
+ // is a caution permission
+ if (caution)
+ {
+ LLChat chat(notice.getString());
+ // LLFloaterChat::addChat(chat, FALSE, FALSE);
+ }
+ }
+}
+
+bool script_question_cb(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ LLMessageSystem *msg = gMessageSystem;
+ S32 orig = notification["payload"]["questions"].asInteger();
+ S32 new_questions = orig;
+
+ // check whether permissions were granted or denied
+ BOOL allowed = TRUE;
+ // the "yes/accept" button is the first button in the template, making it button 0
+ // if any other button was clicked, the permissions were denied
+ if (option != 0)
+ {
+ new_questions = 0;
+ allowed = FALSE;
+ }
+
+ LLUUID task_id = notification["payload"]["task_id"].asUUID();
+ LLUUID item_id = notification["payload"]["item_id"].asUUID();
+
+ // reply with the permissions granted or denied
+ msg->newMessageFast(_PREHASH_ScriptAnswerYes);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_Data);
+ msg->addUUIDFast(_PREHASH_TaskID, task_id);
+ msg->addUUIDFast(_PREHASH_ItemID, item_id);
+ msg->addS32Fast(_PREHASH_Questions, new_questions);
+ msg->sendReliable(LLHost(notification["payload"]["sender"].asString()));
+
+ // only log a chat message if caution prompts are enabled
+ if (gSavedSettings.getBOOL("PermissionsCautionEnabled"))
+ {
+ // log a chat message, if appropriate
+ notify_cautioned_script_question(notification, response, orig, allowed);
+ }
+
+ if ( response["Mute"] ) // mute
+ {
+ LLMuteList::getInstance()->add(LLMute(item_id, notification["payload"]["object_name"].asString(), LLMute::OBJECT));
+
+ // purge the message queue of any previously queued requests from the same source. DEV-4879
+ class OfferMatcher : public LLNotificationsUI::LLScreenChannel::Matcher
+ {
+ public:
+ OfferMatcher(const LLUUID& to_block) : blocked_id(to_block) {}
+ bool matches(const LLNotificationPtr notification) const
+ {
+ if (notification->getName() == "ScriptQuestionCaution"
+ || notification->getName() == "ScriptQuestion")
+ {
+ return (notification->getPayload()["item_id"].asUUID() == blocked_id);
+ }
+ return false;
+ }
+ private:
+ const LLUUID& blocked_id;
+ };
+
+ LLNotificationsUI::LLChannelManager::getInstance()->killToastsFromChannel(LLUUID(
+ gSavedSettings.getString("NotificationChannelUUID")), OfferMatcher(item_id));
+ }
+
+ if (response["Details"])
+ {
+ // respawn notification...
+ LLNotificationsUtil::add(notification["name"], notification["substitutions"], notification["payload"]);
+
+ // ...with description on top
+ LLNotificationsUtil::add("DebitPermissionDetails");
+ }
+ return false;
+}
+static LLNotificationFunctorRegistration script_question_cb_reg_1("ScriptQuestion", script_question_cb);
+static LLNotificationFunctorRegistration script_question_cb_reg_2("ScriptQuestionCaution", script_question_cb);
+
+void process_script_question(LLMessageSystem *msg, void **user_data)
+{
+ // *TODO: Translate owner name -> [FIRST] [LAST]
+
+ LLHost sender = msg->getSender();
+
+ LLUUID taskid;
+ LLUUID itemid;
+ S32 questions;
+ std::string object_name;
+ std::string owner_name;
+
+ // taskid -> object key of object requesting permissions
+ msg->getUUIDFast(_PREHASH_Data, _PREHASH_TaskID, taskid );
+ // itemid -> script asset key of script requesting permissions
+ msg->getUUIDFast(_PREHASH_Data, _PREHASH_ItemID, itemid );
+ msg->getStringFast(_PREHASH_Data, _PREHASH_ObjectName, object_name);
+ msg->getStringFast(_PREHASH_Data, _PREHASH_ObjectOwner, owner_name);
+ msg->getS32Fast(_PREHASH_Data, _PREHASH_Questions, questions );
+
+ // Special case. If the objects are owned by this agent, throttle per-object instead
+ // of per-owner. It's common for residents to reset a ton of scripts that re-request
+ // permissions, as with tier boxes. UUIDs can't be valid agent names and vice-versa,
+ // so we'll reuse the same namespace for both throttle types.
+ std::string throttle_name = owner_name;
+ std::string self_name;
+ LLAgentUI::buildFullname( self_name );
+ if( owner_name == self_name )
+ {
+ throttle_name = taskid.getString();
+ }
+
+ // don't display permission requests if this object is muted
+ if (LLMuteList::getInstance()->isMuted(taskid)) return;
+
+ // throttle excessive requests from any specific user's scripts
+ typedef LLKeyThrottle<std::string> LLStringThrottle;
+ static LLStringThrottle question_throttle( LLREQUEST_PERMISSION_THROTTLE_LIMIT, LLREQUEST_PERMISSION_THROTTLE_INTERVAL );
+
+ switch (question_throttle.noteAction(throttle_name))
+ {
+ case LLStringThrottle::THROTTLE_NEWLY_BLOCKED:
+ LL_INFOS("Messaging") << "process_script_question throttled"
+ << " owner_name:" << owner_name
+ << LL_ENDL;
+ // Fall through
+
+ case LLStringThrottle::THROTTLE_BLOCKED:
+ // Escape altogether until we recover
+ return;
+
+ case LLStringThrottle::THROTTLE_OK:
+ break;
+ }
+
+ std::string script_question;
+ if (questions)
+ {
+ BOOL caution = FALSE;
+ S32 count = 0;
+ LLSD args;
+ args["OBJECTNAME"] = object_name;
+ args["NAME"] = LLCacheName::cleanFullName(owner_name);
+
+ // check the received permission flags against each permission
+ for (S32 i = 0; i < SCRIPT_PERMISSION_EOF; i++)
+ {
+ if (questions & LSCRIPTRunTimePermissionBits[i])
+ {
+ count++;
+ script_question += " " + LLTrans::getString(SCRIPT_QUESTIONS[i]) + "\n";
+
+ // check whether permission question should cause special caution dialog
+ caution |= (SCRIPT_QUESTION_IS_CAUTION[i]);
+ }
+ }
+ args["QUESTIONS"] = script_question;
+
+ LLSD payload;
+ payload["task_id"] = taskid;
+ payload["item_id"] = itemid;
+ payload["sender"] = sender.getIPandPort();
+ payload["questions"] = questions;
+ payload["object_name"] = object_name;
+ payload["owner_name"] = owner_name;
+
+ // check whether cautions are even enabled or not
+ if (gSavedSettings.getBOOL("PermissionsCautionEnabled"))
+ {
+ // display the caution permissions prompt
+ LLNotificationsUtil::add(caution ? "ScriptQuestionCaution" : "ScriptQuestion", args, payload);
+ }
+ else
+ {
+ // fall back to default behavior if cautions are entirely disabled
+ LLNotificationsUtil::add("ScriptQuestion", args, payload);
+ }
+
+ }
+}
+
+
+void process_derez_container(LLMessageSystem *msg, void**)
+{
+ LL_WARNS("Messaging") << "call to deprecated process_derez_container" << LL_ENDL;
+}
+
+void container_inventory_arrived(LLViewerObject* object,
+ LLInventoryObject::object_list_t* inventory,
+ S32 serial_num,
+ void* data)
+{
+ LL_DEBUGS("Messaging") << "container_inventory_arrived()" << LL_ENDL;
+ if( gAgentCamera.cameraMouselook() )
+ {
+ gAgentCamera.changeCameraToDefault();
+ }
+
+ LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel();
+
+ if (inventory->size() > 2)
+ {
+ // create a new inventory category to put this in
+ LLUUID cat_id;
+ cat_id = gInventory.createNewCategory(gInventory.getRootFolderID(),
+ LLFolderType::FT_NONE,
+ LLTrans::getString("AcquiredItems"));
+
+ LLInventoryObject::object_list_t::const_iterator it = inventory->begin();
+ LLInventoryObject::object_list_t::const_iterator end = inventory->end();
+ for ( ; it != end; ++it)
+ {
+ if ((*it)->getType() != LLAssetType::AT_CATEGORY)
+ {
+ LLInventoryObject* obj = (LLInventoryObject*)(*it);
+ LLInventoryItem* item = (LLInventoryItem*)(obj);
+ LLUUID item_id;
+ item_id.generate();
+ time_t creation_date_utc = time_corrected();
+ LLPointer<LLViewerInventoryItem> new_item
+ = new LLViewerInventoryItem(item_id,
+ cat_id,
+ item->getPermissions(),
+ item->getAssetUUID(),
+ item->getType(),
+ item->getInventoryType(),
+ item->getName(),
+ item->getDescription(),
+ LLSaleInfo::DEFAULT,
+ item->getFlags(),
+ creation_date_utc);
+ new_item->updateServer(TRUE);
+ gInventory.updateItem(new_item);
+ }
+ }
+ gInventory.notifyObservers();
+ if(active_panel)
+ {
+ active_panel->setSelection(cat_id, TAKE_FOCUS_NO);
+ }
+ }
+ else if (inventory->size() == 2)
+ {
+ // we're going to get one fake root category as well as the
+ // one actual object
+ LLInventoryObject::object_list_t::iterator it = inventory->begin();
+
+ if ((*it)->getType() == LLAssetType::AT_CATEGORY)
+ {
+ ++it;
+ }
+
+ LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it));
+ const LLUUID category = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(item->getType()));
+
+ LLUUID item_id;
+ item_id.generate();
+ time_t creation_date_utc = time_corrected();
+ LLPointer<LLViewerInventoryItem> new_item
+ = new LLViewerInventoryItem(item_id, category,
+ item->getPermissions(),
+ item->getAssetUUID(),
+ item->getType(),
+ item->getInventoryType(),
+ item->getName(),
+ item->getDescription(),
+ LLSaleInfo::DEFAULT,
+ item->getFlags(),
+ creation_date_utc);
+ new_item->updateServer(TRUE);
+ gInventory.updateItem(new_item);
+ gInventory.notifyObservers();
+ if(active_panel)
+ {
+ active_panel->setSelection(item_id, TAKE_FOCUS_NO);
+ }
+ }
+
+ // we've got the inventory, now delete this object if this was a take
+ BOOL delete_object = (BOOL)(intptr_t)data;
+ LLViewerRegion *region = gAgent.getRegion();
+ if (delete_object && region)
+ {
+ gMessageSystem->newMessageFast(_PREHASH_ObjectDelete);
+ gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+ gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ const U8 NO_FORCE = 0;
+ gMessageSystem->addU8Fast(_PREHASH_Force, NO_FORCE);
+ gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
+ gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID());
+ gMessageSystem->sendReliable(region->getHost());
+ }
+}
+
+// method to format the time.
+std::string formatted_time(const time_t& the_time)
+{
+ std::string dateStr = "["+LLTrans::getString("LTimeWeek")+"] ["
+ +LLTrans::getString("LTimeMonth")+"] ["
+ +LLTrans::getString("LTimeDay")+"] ["
+ +LLTrans::getString("LTimeHour")+"]:["
+ +LLTrans::getString("LTimeMin")+"]:["
+ +LLTrans::getString("LTimeSec")+"] ["
+ +LLTrans::getString("LTimeYear")+"]";
+
+ LLSD substitution;
+ substitution["datetime"] = (S32) the_time;
+ LLStringUtil::format (dateStr, substitution);
+ return dateStr;
+}
+
+
+void process_teleport_failed(LLMessageSystem *msg, void**)
+{
+ std::string reason;
+ std::string big_reason;
+ LLSD args;
+
+ // if we have additional alert data
+ if (msg->has(_PREHASH_AlertInfo) && msg->getSizeFast(_PREHASH_AlertInfo, _PREHASH_Message) > 0)
+ {
+ // Get the message ID
+ msg->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, reason);
+ big_reason = LLAgent::sTeleportErrorMessages[reason];
+ if ( big_reason.size() > 0 )
+ { // Substitute verbose reason from the local map
+ args["REASON"] = big_reason;
+ }
+ else
+ { // Nothing found in the map - use what the server returned in the original message block
+ msg->getStringFast(_PREHASH_Info, _PREHASH_Reason, reason);
+ args["REASON"] = reason;
+ }
+
+ LLSD llsd_block;
+ std::string llsd_raw;
+ msg->getStringFast(_PREHASH_AlertInfo, _PREHASH_ExtraParams, llsd_raw);
+ if (llsd_raw.length())
+ {
+ std::istringstream llsd_data(llsd_raw);
+ if (!LLSDSerialize::deserialize(llsd_block, llsd_data, llsd_raw.length()))
+ {
+ llwarns << "process_teleport_failed: Attempted to read alert parameter data into LLSD but failed:" << llsd_raw << llendl;
+ }
+ else
+ {
+ // change notification name in this special case
+ if (handle_special_notification("RegionEntryAccessBlocked", llsd_block))
+ {
+ if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE )
+ {
+ gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
+ }
+ return;
+ }
+ }
+ }
+
+ }
+ else
+ {
+ msg->getStringFast(_PREHASH_Info, _PREHASH_Reason, reason);
+
+ big_reason = LLAgent::sTeleportErrorMessages[reason];
+ if ( big_reason.size() > 0 )
+ { // Substitute verbose reason from the local map
+ args["REASON"] = big_reason;
+ }
+ else
+ { // Nothing found in the map - use what the server returned
+ args["REASON"] = reason;
+ }
+ }
+
+ LLNotificationsUtil::add("CouldNotTeleportReason", args);
+
+ // Let the interested parties know that teleport failed.
+ LLViewerParcelMgr::getInstance()->onTeleportFailed();
+
+ if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE )
+ {
+ gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
+ }
+}
+
+void process_teleport_local(LLMessageSystem *msg,void**)
+{
+ LLUUID agent_id;
+ msg->getUUIDFast(_PREHASH_Info, _PREHASH_AgentID, agent_id);
+ if (agent_id != gAgent.getID())
+ {
+ LL_WARNS("Messaging") << "Got teleport notification for wrong agent!" << LL_ENDL;
+ return;
+ }
+
+ U32 location_id;
+ LLVector3 pos, look_at;
+ U32 teleport_flags;
+ msg->getU32Fast(_PREHASH_Info, _PREHASH_LocationID, location_id);
+ msg->getVector3Fast(_PREHASH_Info, _PREHASH_Position, pos);
+ msg->getVector3Fast(_PREHASH_Info, _PREHASH_LookAt, look_at);
+ msg->getU32Fast(_PREHASH_Info, _PREHASH_TeleportFlags, teleport_flags);
+
+ if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE )
+ {
+ if( gAgent.getTeleportState() == LLAgent::TELEPORT_LOCAL )
+ {
+ // To prevent TeleportStart messages re-activating the progress screen right
+ // after tp, keep the teleport state and let progress screen clear it after a short delay
+ // (progress screen is active but not visible) *TODO: remove when SVC-5290 is fixed
+ gTeleportDisplayTimer.reset();
+ gTeleportDisplay = TRUE;
+ }
+ else
+ {
+ gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
+ }
+ }
+
+ // Sim tells us whether the new position is off the ground
+ if (teleport_flags & TELEPORT_FLAGS_IS_FLYING)
+ {
+ gAgent.setFlying(TRUE);
+ }
+ else
+ {
+ gAgent.setFlying(FALSE);
+ }
+
+ gAgent.setPositionAgent(pos);
+ gAgentCamera.slamLookAt(look_at);
+
+ if ( !(gAgent.getTeleportKeepsLookAt() && LLViewerJoystick::getInstance()->getOverrideCamera()) )
+ {
+ gAgentCamera.resetView(TRUE, TRUE);
+ }
+
+ // send camera update to new region
+ gAgentCamera.updateCamera();
+
+ send_agent_update(TRUE, TRUE);
+
+ // Let the interested parties know we've teleported.
+ // Vadim *HACK: Agent position seems to get reset (to render position?)
+ // on each frame, so we have to pass the new position manually.
+ LLViewerParcelMgr::getInstance()->onTeleportFinished(true, gAgent.getPosGlobalFromAgent(pos));
+}
+
+void send_simple_im(const LLUUID& to_id,
+ const std::string& message,
+ EInstantMessage dialog,
+ const LLUUID& id)
+{
+ std::string my_name;
+ LLAgentUI::buildFullname(my_name);
+ send_improved_im(to_id,
+ my_name,
+ message,
+ IM_ONLINE,
+ dialog,
+ id,
+ NO_TIMESTAMP,
+ (U8*)EMPTY_BINARY_BUCKET,
+ EMPTY_BINARY_BUCKET_SIZE);
+}
+
+void send_group_notice(const LLUUID& group_id,
+ const std::string& subject,
+ const std::string& message,
+ const LLInventoryItem* item)
+{
+ // Put this notice into an instant message form.
+ // This will mean converting the item to a binary bucket,
+ // and the subject/message into a single field.
+ std::string my_name;
+ LLAgentUI::buildFullname(my_name);
+
+ // Combine subject + message into a single string.
+ std::ostringstream subject_and_message;
+ // TODO: turn all existing |'s into ||'s in subject and message.
+ subject_and_message << subject << "|" << message;
+
+ // Create an empty binary bucket.
+ U8 bin_bucket[MAX_INVENTORY_BUFFER_SIZE];
+ U8* bucket_to_send = bin_bucket;
+ bin_bucket[0] = '\0';
+ S32 bin_bucket_size = EMPTY_BINARY_BUCKET_SIZE;
+ // If there is an item being sent, pack it into the binary bucket.
+ if (item)
+ {
+ LLSD item_def;
+ item_def["item_id"] = item->getUUID();
+ item_def["owner_id"] = item->getPermissions().getOwner();
+ std::ostringstream ostr;
+ LLSDSerialize::serialize(item_def, ostr, LLSDSerialize::LLSD_XML);
+ bin_bucket_size = ostr.str().copy(
+ (char*)bin_bucket, ostr.str().size());
+ bin_bucket[bin_bucket_size] = '\0';
+ }
+ else
+ {
+ bucket_to_send = (U8*) EMPTY_BINARY_BUCKET;
+ }
+
+
+ send_improved_im(
+ group_id,
+ my_name,
+ subject_and_message.str(),
+ IM_ONLINE,
+ IM_GROUP_NOTICE,
+ LLUUID::null,
+ NO_TIMESTAMP,
+ bucket_to_send,
+ bin_bucket_size);
+}
+
+bool handle_lure_callback(const LLSD& notification, const LLSD& response)
+{
+ std::string text = response["message"].asString();
+ LLSLURL slurl;
+ LLAgentUI::buildSLURL(slurl);
+ text.append("\r\n").append(slurl.getSLURLString());
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+
+ if(0 == option)
+ {
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_StartLure);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_Info);
+ msg->addU8Fast(_PREHASH_LureType, (U8)0); // sim will fill this in.
+ msg->addStringFast(_PREHASH_Message, text);
+ for(LLSD::array_const_iterator it = notification["payload"]["ids"].beginArray();
+ it != notification["payload"]["ids"].endArray();
+ ++it)
+ {
+ LLUUID target_id = it->asUUID();
+
+ msg->nextBlockFast(_PREHASH_TargetData);
+ msg->addUUIDFast(_PREHASH_TargetID, target_id);
+
+ // Record the offer.
+ {
+ std::string target_name;
+ gCacheName->getFullName(target_id, target_name); // for im log filenames
+ LLSD args;
+ args["TO_NAME"] = LLSLURL("agent", target_id, "displayname").getSLURLString();;
+
+ LLSD payload;
+
+ //*TODO please rewrite all keys to the same case, lower or upper
+ payload["from_id"] = target_id;
+ payload["SUPPRESS_TOAST"] = true;
+ LLNotificationsUtil::add("TeleportOfferSent", args, payload);
+
+ // Add the recepient to the recent people list.
+ LLRecentPeople::instance().add(target_id);
+ }
+ }
+ gAgent.sendReliableMessage();
+ }
+
+ return false;
+}
+
+void handle_lure(const LLUUID& invitee)
+{
+ LLDynamicArray<LLUUID> ids;
+ ids.push_back(invitee);
+ handle_lure(ids);
+}
+
+// Prompt for a message to the invited user.
+void handle_lure(const uuid_vec_t& ids)
+{
+ if (ids.empty()) return;
+
+ if (!gAgent.getRegion()) return;
+
+ LLSD edit_args;
+ edit_args["REGION"] = gAgent.getRegion()->getName();
+
+ LLSD payload;
+ for (LLDynamicArray<LLUUID>::const_iterator it = ids.begin();
+ it != ids.end();
+ ++it)
+ {
+ payload["ids"].append(*it);
+ }
+ if (gAgent.isGodlike())
+ {
+ LLNotificationsUtil::add("OfferTeleportFromGod", edit_args, payload, handle_lure_callback);
+ }
+ else
+ {
+ LLNotificationsUtil::add("OfferTeleport", edit_args, payload, handle_lure_callback);
+ }
+}
+
+
+void send_improved_im(const LLUUID& to_id,
+ const std::string& name,
+ const std::string& message,
+ U8 offline,
+ EInstantMessage dialog,
+ const LLUUID& id,
+ U32 timestamp,
+ const U8* binary_bucket,
+ S32 binary_bucket_size)
+{
+ pack_instant_message(
+ gMessageSystem,
+ gAgent.getID(),
+ FALSE,
+ gAgent.getSessionID(),
+ to_id,
+ name,
+ message,
+ offline,
+ dialog,
+ id,
+ 0,
+ LLUUID::null,
+ gAgent.getPositionAgent(),
+ timestamp,
+ binary_bucket,
+ binary_bucket_size);
+ gAgent.sendReliableMessage();
+}
+
+
+void send_places_query(const LLUUID& query_id,
+ const LLUUID& trans_id,
+ const std::string& query_text,
+ U32 query_flags,
+ S32 category,
+ const std::string& sim_name)
+{
+ LLMessageSystem* msg = gMessageSystem;
+
+ msg->newMessage("PlacesQuery");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID", gAgent.getID());
+ msg->addUUID("SessionID", gAgent.getSessionID());
+ msg->addUUID("QueryID", query_id);
+ msg->nextBlock("TransactionData");
+ msg->addUUID("TransactionID", trans_id);
+ msg->nextBlock("QueryData");
+ msg->addString("QueryText", query_text);
+ msg->addU32("QueryFlags", query_flags);
+ msg->addS8("Category", (S8)category);
+ msg->addString("SimName", sim_name);
+ gAgent.sendReliableMessage();
+}
+
+
+void process_user_info_reply(LLMessageSystem* msg, void**)
+{
+ LLUUID agent_id;
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
+ if(agent_id != gAgent.getID())
+ {
+ LL_WARNS("Messaging") << "process_user_info_reply - "
+ << "wrong agent id." << LL_ENDL;
+ }
+
+ BOOL im_via_email;
+ msg->getBOOLFast(_PREHASH_UserData, _PREHASH_IMViaEMail, im_via_email);
+ std::string email;
+ msg->getStringFast(_PREHASH_UserData, _PREHASH_EMail, email);
+ std::string dir_visibility;
+ msg->getString( "UserData", "DirectoryVisibility", dir_visibility);
+
+ LLFloaterPreference::updateUserInfo(dir_visibility, im_via_email, email);
+ LLFloaterPostcard::updateUserInfo(email);
+}
+
+
+//---------------------------------------------------------------------------
+// Script Dialog
+//---------------------------------------------------------------------------
+
+const S32 SCRIPT_DIALOG_MAX_BUTTONS = 12;
+const S32 SCRIPT_DIALOG_BUTTON_STR_SIZE = 24;
+const S32 SCRIPT_DIALOG_MAX_MESSAGE_SIZE = 512;
+const char* SCRIPT_DIALOG_HEADER = "Script Dialog:\n";
+
+bool callback_script_dialog(const LLSD& notification, const LLSD& response)
+{
+ LLNotificationForm form(notification["form"]);
+
+ std::string rtn_text;
+ S32 button_idx;
+ button_idx = LLNotification::getSelectedOption(notification, response);
+ if (response[TEXTBOX_MAGIC_TOKEN].isDefined())
+ {
+ if (response[TEXTBOX_MAGIC_TOKEN].isString())
+ rtn_text = response[TEXTBOX_MAGIC_TOKEN].asString();
+ else
+ rtn_text.clear(); // bool marks empty string
+ }
+ else
+ {
+ rtn_text = LLNotification::getSelectedOptionName(response);
+ }
+
+ // Didn't click "Ignore"
+ if (button_idx != -1)
+ {
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessage("ScriptDialogReply");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID", gAgent.getID());
+ msg->addUUID("SessionID", gAgent.getSessionID());
+ msg->nextBlock("Data");
+ msg->addUUID("ObjectID", notification["payload"]["object_id"].asUUID());
+ msg->addS32("ChatChannel", notification["payload"]["chat_channel"].asInteger());
+ msg->addS32("ButtonIndex", button_idx);
+ msg->addString("ButtonLabel", rtn_text);
+ msg->sendReliable(LLHost(notification["payload"]["sender"].asString()));
+ }
+
+ return false;
+}
+static LLNotificationFunctorRegistration callback_script_dialog_reg_1("ScriptDialog", callback_script_dialog);
+static LLNotificationFunctorRegistration callback_script_dialog_reg_2("ScriptDialogGroup", callback_script_dialog);
+
+void process_script_dialog(LLMessageSystem* msg, void**)
+{
+ S32 i;
+ LLSD payload;
+
+ LLUUID object_id;
+ msg->getUUID("Data", "ObjectID", object_id);
+
+ if (LLMuteList::getInstance()->isMuted(object_id))
+ {
+ return;
+ }
+
+ std::string message;
+ std::string first_name;
+ std::string last_name;
+ std::string title;
+
+ S32 chat_channel;
+ msg->getString("Data", "FirstName", first_name);
+ msg->getString("Data", "LastName", last_name);
+ msg->getString("Data", "ObjectName", title);
+ msg->getString("Data", "Message", message);
+ msg->getS32("Data", "ChatChannel", chat_channel);
+
+ // unused for now
+ LLUUID image_id;
+ msg->getUUID("Data", "ImageID", image_id);
+
+ payload["sender"] = msg->getSender().getIPandPort();
+ payload["object_id"] = object_id;
+ payload["chat_channel"] = chat_channel;
+
+ // build up custom form
+ S32 button_count = msg->getNumberOfBlocks("Buttons");
+ if (button_count > SCRIPT_DIALOG_MAX_BUTTONS)
+ {
+ llwarns << "Too many script dialog buttons - omitting some" << llendl;
+ button_count = SCRIPT_DIALOG_MAX_BUTTONS;
+ }
+
+ LLNotificationForm form;
+ for (i = 0; i < button_count; i++)
+ {
+ std::string tdesc;
+ msg->getString("Buttons", "ButtonLabel", tdesc, i);
+ form.addElement("button", std::string(tdesc));
+ }
+
+ LLSD args;
+ args["TITLE"] = title;
+ args["MESSAGE"] = message;
+ LLNotificationPtr notification;
+ if (!first_name.empty())
+ {
+ args["NAME"] = LLCacheName::buildFullName(first_name, last_name);
+ notification = LLNotifications::instance().add(
+ LLNotification::Params("ScriptDialog").substitutions(args).payload(payload).form_elements(form.asLLSD()));
+ }
+ else
+ {
+ args["GROUPNAME"] = last_name;
+ notification = LLNotifications::instance().add(
+ LLNotification::Params("ScriptDialogGroup").substitutions(args).payload(payload).form_elements(form.asLLSD()));
+ }
+}
+
+//---------------------------------------------------------------------------
+
+
+std::vector<LLSD> gLoadUrlList;
+
+bool callback_load_url(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+
+ if (0 == option)
+ {
+ LLWeb::loadURL(notification["payload"]["url"].asString());
+ }
+
+ return false;
+}
+static LLNotificationFunctorRegistration callback_load_url_reg("LoadWebPage", callback_load_url);
+
+
+// We've got the name of the person who owns the object hurling the url.
+// Display confirmation dialog.
+void callback_load_url_name(const LLUUID& id, const std::string& full_name, bool is_group)
+{
+ std::vector<LLSD>::iterator it;
+ for (it = gLoadUrlList.begin(); it != gLoadUrlList.end(); )
+ {
+ LLSD load_url_info = *it;
+ if (load_url_info["owner_id"].asUUID() == id)
+ {
+ it = gLoadUrlList.erase(it);
+
+ std::string owner_name;
+ if (is_group)
+ {
+ owner_name = full_name + LLTrans::getString("Group");
+ }
+ else
+ {
+ owner_name = full_name;
+ }
+
+ // For legacy name-only mutes.
+ if (LLMuteList::getInstance()->isMuted(LLUUID::null, owner_name))
+ {
+ continue;
+ }
+ LLSD args;
+ args["URL"] = load_url_info["url"].asString();
+ args["MESSAGE"] = load_url_info["message"].asString();;
+ args["OBJECTNAME"] = load_url_info["object_name"].asString();
+ args["NAME"] = owner_name;
+
+ LLNotificationsUtil::add("LoadWebPage", args, load_url_info);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+}
+
+void process_load_url(LLMessageSystem* msg, void**)
+{
+ LLUUID object_id;
+ LLUUID owner_id;
+ BOOL owner_is_group;
+ char object_name[256]; /* Flawfinder: ignore */
+ char message[256]; /* Flawfinder: ignore */
+ char url[256]; /* Flawfinder: ignore */
+
+ msg->getString("Data", "ObjectName", 256, object_name);
+ msg->getUUID( "Data", "ObjectID", object_id);
+ msg->getUUID( "Data", "OwnerID", owner_id);
+ msg->getBOOL( "Data", "OwnerIsGroup", owner_is_group);
+ msg->getString("Data", "Message", 256, message);
+ msg->getString("Data", "URL", 256, url);
+
+ LLSD payload;
+ payload["object_id"] = object_id;
+ payload["owner_id"] = owner_id;
+ payload["owner_is_group"] = owner_is_group;
+ payload["object_name"] = object_name;
+ payload["message"] = message;
+ payload["url"] = url;
+
+ // URL is safety checked in load_url above
+
+ // Check if object or owner is muted
+ if (LLMuteList::getInstance()->isMuted(object_id, object_name) ||
+ LLMuteList::getInstance()->isMuted(owner_id))
+ {
+ LL_INFOS("Messaging")<<"Ignoring load_url from muted object/owner."<<LL_ENDL;
+ return;
+ }
+
+ // Add to list of pending name lookups
+ gLoadUrlList.push_back(payload);
+
+ gCacheName->get(owner_id, owner_is_group,
+ boost::bind(&callback_load_url_name, _1, _2, _3));
+}
+
+
+void callback_download_complete(void** data, S32 result, LLExtStat ext_status)
+{
+ std::string* filepath = (std::string*)data;
+ LLSD args;
+ args["DOWNLOAD_PATH"] = *filepath;
+ LLNotificationsUtil::add("FinishedRawDownload", args);
+ delete filepath;
+}
+
+
+void process_initiate_download(LLMessageSystem* msg, void**)
+{
+ LLUUID agent_id;
+ msg->getUUID("AgentData", "AgentID", agent_id);
+ if (agent_id != gAgent.getID())
+ {
+ LL_WARNS("Messaging") << "Initiate download for wrong agent" << LL_ENDL;
+ return;
+ }
+
+ std::string sim_filename;
+ std::string viewer_filename;
+ msg->getString("FileData", "SimFilename", sim_filename);
+ msg->getString("FileData", "ViewerFilename", viewer_filename);
+
+ if (!gXferManager->validateFileForRequest(viewer_filename))
+ {
+ llwarns << "SECURITY: Unauthorized download to local file " << viewer_filename << llendl;
+ return;
+ }
+ gXferManager->requestFile(viewer_filename,
+ sim_filename,
+ LL_PATH_NONE,
+ msg->getSender(),
+ FALSE, // don't delete remote
+ callback_download_complete,
+ (void**)new std::string(viewer_filename));
+}
+
+
+void process_script_teleport_request(LLMessageSystem* msg, void**)
+{
+ if (!gSavedSettings.getBOOL("ScriptsCanShowUI")) return;
+
+ std::string object_name;
+ std::string sim_name;
+ LLVector3 pos;
+ LLVector3 look_at;
+
+ msg->getString("Data", "ObjectName", object_name);
+ msg->getString("Data", "SimName", sim_name);
+ msg->getVector3("Data", "SimPosition", pos);
+ msg->getVector3("Data", "LookAt", look_at);
+
+ LLFloaterWorldMap* instance = LLFloaterWorldMap::getInstance();
+ if(instance)
+ {
+ instance->trackURL(
+ sim_name, (S32)pos.mV[VX], (S32)pos.mV[VY], (S32)pos.mV[VZ]);
+ LLFloaterReg::showInstance("world_map", "center");
+ }
+
+ // remove above two lines and replace with below line
+ // to re-enable parcel browser for llMapDestination()
+ // LLURLDispatcher::dispatch(LLSLURL::buildSLURL(sim_name, (S32)pos.mV[VX], (S32)pos.mV[VY], (S32)pos.mV[VZ]), FALSE);
+
+}
+
+void process_covenant_reply(LLMessageSystem* msg, void**)
+{
+ LLUUID covenant_id, estate_owner_id;
+ std::string estate_name;
+ U32 covenant_timestamp;
+ msg->getUUID("Data", "CovenantID", covenant_id);
+ msg->getU32("Data", "CovenantTimestamp", covenant_timestamp);
+ msg->getString("Data", "EstateName", estate_name);
+ msg->getUUID("Data", "EstateOwnerID", estate_owner_id);
+
+ LLPanelEstateCovenant::updateEstateName(estate_name);
+ LLPanelLandCovenant::updateEstateName(estate_name);
+ LLFloaterBuyLand::updateEstateName(estate_name);
+
+ std::string owner_name =
+ LLSLURL("agent", estate_owner_id, "inspect").getSLURLString();
+ LLPanelEstateCovenant::updateEstateOwnerName(owner_name);
+ LLPanelLandCovenant::updateEstateOwnerName(owner_name);
+ LLFloaterBuyLand::updateEstateOwnerName(owner_name);
+
+ LLPanelPlaceProfile* panel = LLSideTray::getInstance()->getPanel<LLPanelPlaceProfile>("panel_place_profile");
+ if (panel)
+ {
+ panel->updateEstateName(estate_name);
+ panel->updateEstateOwnerName(owner_name);
+ }
+
+ // standard message, not from system
+ std::string last_modified;
+ if (covenant_timestamp == 0)
+ {
+ last_modified = LLTrans::getString("covenant_last_modified")+LLTrans::getString("never_text");
+ }
+ else
+ {
+ last_modified = LLTrans::getString("covenant_last_modified")+"["
+ +LLTrans::getString("LTimeWeek")+"] ["
+ +LLTrans::getString("LTimeMonth")+"] ["
+ +LLTrans::getString("LTimeDay")+"] ["
+ +LLTrans::getString("LTimeHour")+"]:["
+ +LLTrans::getString("LTimeMin")+"]:["
+ +LLTrans::getString("LTimeSec")+"] ["
+ +LLTrans::getString("LTimeYear")+"]";
+ LLSD substitution;
+ substitution["datetime"] = (S32) covenant_timestamp;
+ LLStringUtil::format (last_modified, substitution);
+ }
+
+ LLPanelEstateCovenant::updateLastModified(last_modified);
+ LLPanelLandCovenant::updateLastModified(last_modified);
+ LLFloaterBuyLand::updateLastModified(last_modified);
+
+ // load the actual covenant asset data
+ const BOOL high_priority = TRUE;
+ if (covenant_id.notNull())
+ {
+ gAssetStorage->getEstateAsset(gAgent.getRegionHost(),
+ gAgent.getID(),
+ gAgent.getSessionID(),
+ covenant_id,
+ LLAssetType::AT_NOTECARD,
+ ET_Covenant,
+ onCovenantLoadComplete,
+ NULL,
+ high_priority);
+ }
+ else
+ {
+ std::string covenant_text;
+ if (estate_owner_id.isNull())
+ {
+ // mainland
+ covenant_text = LLTrans::getString("RegionNoCovenant");
+ }
+ else
+ {
+ covenant_text = LLTrans::getString("RegionNoCovenantOtherOwner");
+ }
+ LLPanelEstateCovenant::updateCovenantText(covenant_text, covenant_id);
+ LLPanelLandCovenant::updateCovenantText(covenant_text);
+ LLFloaterBuyLand::updateCovenantText(covenant_text, covenant_id);
+ if (panel)
+ {
+ panel->updateCovenantText(covenant_text);
+ }
+ }
+}
+
+void onCovenantLoadComplete(LLVFS *vfs,
+ const LLUUID& asset_uuid,
+ LLAssetType::EType type,
+ void* user_data, S32 status, LLExtStat ext_status)
+{
+ LL_DEBUGS("Messaging") << "onCovenantLoadComplete()" << LL_ENDL;
+ std::string covenant_text;
+ if(0 == status)
+ {
+ LLVFile file(vfs, asset_uuid, type, LLVFile::READ);
+
+ S32 file_length = file.getSize();
+
+ std::vector<char> buffer(file_length+1);
+ file.read((U8*)&buffer[0], file_length);
+ // put a EOS at the end
+ buffer[file_length] = '\0';
+
+ if( (file_length > 19) && !strncmp( &buffer[0], "Linden text version", 19 ) )
+ {
+ LLViewerTextEditor::Params params;
+ params.name("temp");
+ params.max_text_length(file_length+1);
+ LLViewerTextEditor * editor = LLUICtrlFactory::create<LLViewerTextEditor> (params);
+ if( !editor->importBuffer( &buffer[0], file_length+1 ) )
+ {
+ LL_WARNS("Messaging") << "Problem importing estate covenant." << LL_ENDL;
+ covenant_text = "Problem importing estate covenant.";
+ }
+ else
+ {
+ // Version 0 (just text, doesn't include version number)
+ covenant_text = editor->getText();
+ }
+ delete editor;
+ }
+ else
+ {
+ LL_WARNS("Messaging") << "Problem importing estate covenant: Covenant file format error." << LL_ENDL;
+ covenant_text = "Problem importing estate covenant: Covenant file format error.";
+ }
+ }
+ else
+ {
+ LLViewerStats::getInstance()->incStat( LLViewerStats::ST_DOWNLOAD_FAILED );
+
+ if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ||
+ LL_ERR_FILE_EMPTY == status)
+ {
+ covenant_text = "Estate covenant notecard is missing from database.";
+ }
+ else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status)
+ {
+ covenant_text = "Insufficient permissions to view estate covenant.";
+ }
+ else
+ {
+ covenant_text = "Unable to load estate covenant at this time.";
+ }
+
+ LL_WARNS("Messaging") << "Problem loading notecard: " << status << LL_ENDL;
+ }
+ LLPanelEstateCovenant::updateCovenantText(covenant_text, asset_uuid);
+ LLPanelLandCovenant::updateCovenantText(covenant_text);
+ LLFloaterBuyLand::updateCovenantText(covenant_text, asset_uuid);
+
+ LLPanelPlaceProfile* panel = LLSideTray::getInstance()->getPanel<LLPanelPlaceProfile>("panel_place_profile");
+ if (panel)
+ {
+ panel->updateCovenantText(covenant_text);
+ }
+}
+
+
+void process_feature_disabled_message(LLMessageSystem* msg, void**)
+{
+ // Handle Blacklisted feature simulator response...
+ LLUUID agentID;
+ LLUUID transactionID;
+ std::string messageText;
+ msg->getStringFast(_PREHASH_FailureInfo,_PREHASH_ErrorMessage, messageText,0);
+ msg->getUUIDFast(_PREHASH_FailureInfo,_PREHASH_AgentID,agentID);
+ msg->getUUIDFast(_PREHASH_FailureInfo,_PREHASH_TransactionID,transactionID);
+
+ LL_WARNS("Messaging") << "Blacklisted Feature Response:" << messageText << LL_ENDL;
+}
+
+// ------------------------------------------------------------
+// Message system exception callbacks
+// ------------------------------------------------------------
+
+void invalid_message_callback(LLMessageSystem* msg,
+ void*,
+ EMessageException exception)
+{
+ LLAppViewer::instance()->badNetworkHandler();
+}
+
+// Please do not add more message handlers here. This file is huge.
+// Put them in a file related to the functionality you are implementing.
+
+void LLOfferInfo::forceResponse(InventoryOfferResponse response)
+{
+ LLNotification::Params params("UserGiveItem");
+ params.functor.function(boost::bind(&LLOfferInfo::inventory_offer_callback, this, _1, _2));
+ LLNotifications::instance().forceResponse(params, response);
+}
+
diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index 40f0b43313..dfa35edef4 100644 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -539,6 +539,12 @@ void LLViewerParcelMedia::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent }; break; + case MEDIA_EVENT_NAVIGATE_ERROR_PAGE: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_ERROR_PAGE" << LL_ENDL; + }; + break; + case MEDIA_EVENT_CLICK_LINK_HREF: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << self->getClickTarget() << "\", uri is " << self->getClickURL() << LL_ENDL; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 147163a9c0..0778536d15 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1,5034 +1,5040 @@ -/** - * @file llviewerwindow.cpp - * @brief Implementation of the LLViewerWindow class. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llviewerwindow.h" - -#if LL_WINDOWS -#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally -#endif - -// system library includes -#include <stdio.h> -#include <iostream> -#include <fstream> -#include <algorithm> - -#include "llagent.h" -#include "llagentcamera.h" -#include "llfloaterreg.h" -#include "llpanellogin.h" -#include "llviewerkeyboard.h" -#include "llviewermenu.h" - -#include "llviewquery.h" -#include "llxmltree.h" -#include "llslurl.h" -//#include "llviewercamera.h" -#include "llrender.h" - -#include "llvoiceclient.h" // for push-to-talk button handling - -// -// TODO: Many of these includes are unnecessary. Remove them. -// - -// linden library includes -#include "llaudioengine.h" // mute on minimize -#include "indra_constants.h" -#include "llassetstorage.h" -#include "llerrorcontrol.h" -#include "llfontgl.h" -#include "llmousehandler.h" -#include "llrect.h" -#include "llsky.h" -#include "llstring.h" -#include "llui.h" -#include "lluuid.h" -#include "llview.h" -#include "llxfermanager.h" -#include "message.h" -#include "object_flags.h" -#include "lltimer.h" -#include "timing.h" -#include "llviewermenu.h" -#include "lltooltip.h" -#include "llmediaentry.h" -#include "llurldispatcher.h" - -// newview includes -#include "llagent.h" -#include "llbox.h" -#include "llconsole.h" -#include "llviewercontrol.h" -#include "llcylinder.h" -#include "lldebugview.h" -#include "lldir.h" -#include "lldrawable.h" -#include "lldrawpoolalpha.h" -#include "lldrawpoolbump.h" -#include "lldrawpoolwater.h" -#include "llmaniptranslate.h" -#include "llface.h" -#include "llfeaturemanager.h" -#include "llfilepicker.h" -#include "llfirstuse.h" -#include "llfloater.h" -#include "llfloaterbuildoptions.h" -#include "llfloaterbuyland.h" -#include "llfloatercamera.h" -#include "llfloaterland.h" -#include "llfloaterinspect.h" -#include "llfloatermap.h" -#include "llfloaternamedesc.h" -#include "llfloaterpreference.h" -#include "llfloatersnapshot.h" -#include "llfloatertools.h" -#include "llfloaterworldmap.h" -#include "llfocusmgr.h" -#include "llfontfreetype.h" -#include "llgesturemgr.h" -#include "llglheaders.h" -#include "lltooltip.h" -#include "llhudmanager.h" -#include "llhudobject.h" -#include "llhudview.h" -#include "llimagebmp.h" -#include "llimagej2c.h" -#include "llimageworker.h" -#include "llkeyboard.h" -#include "lllineeditor.h" -#include "llmenugl.h" -#include "llmodaldialog.h" -#include "llmorphview.h" -#include "llmoveview.h" -#include "llnavigationbar.h" -#include "llpopupview.h" -#include "llpreviewtexture.h" -#include "llprogressview.h" -#include "llresmgr.h" -#include "llsidetray.h" -#include "llselectmgr.h" -#include "llrootview.h" -#include "llrendersphere.h" -#include "llstartup.h" -#include "llstatusbar.h" -#include "llstatview.h" -#include "llsurface.h" -#include "llsurfacepatch.h" -#include "lltexlayer.h" -#include "lltextbox.h" -#include "lltexturecache.h" -#include "lltexturefetch.h" -#include "lltextureview.h" -#include "lltool.h" -#include "lltoolcomp.h" -#include "lltooldraganddrop.h" -#include "lltoolface.h" -#include "lltoolfocus.h" -#include "lltoolgrab.h" -#include "lltoolmgr.h" -#include "lltoolmorph.h" -#include "lltoolpie.h" -#include "lltoolselectland.h" -#include "lltrans.h" -#include "lluictrlfactory.h" -#include "llurldispatcher.h" // SLURL from other app instance -#include "llversioninfo.h" -#include "llvieweraudio.h" -#include "llviewercamera.h" -#include "llviewergesture.h" -#include "llviewertexturelist.h" -#include "llviewerinventory.h" -#include "llviewerkeyboard.h" -#include "llviewermedia.h" -#include "llviewermediafocus.h" -#include "llviewermenu.h" -#include "llviewermessage.h" -#include "llviewerobjectlist.h" -#include "llviewerparcelmgr.h" -#include "llviewerregion.h" -#include "llviewershadermgr.h" -#include "llviewerstats.h" -#include "llvoavatarself.h" -#include "llvovolume.h" -#include "llworld.h" -#include "llworldmapview.h" -#include "pipeline.h" -#include "llappviewer.h" -#include "llviewerdisplay.h" -#include "llspatialpartition.h" -#include "llviewerjoystick.h" -#include "llviewernetwork.h" -#include "llpostprocess.h" -#include "llbottomtray.h" -#include "llnearbychatbar.h" -#include "llagentui.h" -#include "llwearablelist.h" - -#include "llnotifications.h" -#include "llnotificationsutil.h" -#include "llnotificationmanager.h" - -#include "llfloaternotificationsconsole.h" - -#include "llnearbychat.h" -#include "llviewerwindowlistener.h" -#include "llpaneltopinfobar.h" - -#if LL_WINDOWS -#include <tchar.h> // For Unicode conversion methods -#endif - -// -// Globals -// -void render_ui(F32 zoom_factor = 1.f, int subfield = 0); - -extern BOOL gDebugClicks; -extern BOOL gDisplaySwapBuffers; -extern BOOL gDepthDirty; -extern BOOL gResizeScreenTexture; - -LLViewerWindow *gViewerWindow = NULL; - -LLFrameTimer gAwayTimer; -LLFrameTimer gAwayTriggerTimer; - -BOOL gShowOverlayTitle = FALSE; - -LLViewerObject* gDebugRaycastObject = NULL; -LLVector3 gDebugRaycastIntersection; -LLVector2 gDebugRaycastTexCoord; -LLVector3 gDebugRaycastNormal; -LLVector3 gDebugRaycastBinormal; -S32 gDebugRaycastFaceHit; - -// HUD display lines in lower right -BOOL gDisplayWindInfo = FALSE; -BOOL gDisplayCameraPos = FALSE; -BOOL gDisplayFOV = FALSE; -BOOL gDisplayBadge = FALSE; - -S32 CHAT_BAR_HEIGHT = 28; -S32 OVERLAY_BAR_HEIGHT = 20; - -const U8 NO_FACE = 255; -BOOL gQuietSnapshot = FALSE; - -const F32 MIN_AFK_TIME = 2.f; // minimum time after setting away state before coming back -const F32 MAX_FAST_FRAME_TIME = 0.5f; -const F32 FAST_FRAME_INCREMENT = 0.1f; - -const F32 MIN_DISPLAY_SCALE = 0.75f; - -std::string LLViewerWindow::sSnapshotBaseName; -std::string LLViewerWindow::sSnapshotDir; - -std::string LLViewerWindow::sMovieBaseName; - -class RecordToChatConsole : public LLError::Recorder, public LLSingleton<RecordToChatConsole> -{ -public: - virtual void recordMessage(LLError::ELevel level, - const std::string& message) - { - //FIXME: this is NOT thread safe, and will do bad things when a warning is issued from a non-UI thread - - // only log warnings to chat console - //if (level == LLError::LEVEL_WARN) - //{ - //LLFloaterChat* chat_floater = LLFloaterReg::findTypedInstance<LLFloaterChat>("chat"); - //if (chat_floater && gSavedSettings.getBOOL("WarningsAsChat")) - //{ - // LLChat chat; - // chat.mText = message; - // chat.mSourceType = CHAT_SOURCE_SYSTEM; - - // chat_floater->addChat(chat, FALSE, FALSE); - //} - //} - } -}; - -//////////////////////////////////////////////////////////////////////////// -// -// LLDebugText -// - -class LLDebugText -{ -private: - struct Line - { - Line(const std::string& in_text, S32 in_x, S32 in_y) : text(in_text), x(in_x), y(in_y) {} - std::string text; - S32 x,y; - }; - - LLViewerWindow *mWindow; - - typedef std::vector<Line> line_list_t; - line_list_t mLineList; - LLColor4 mTextColor; - - void addText(S32 x, S32 y, const std::string &text) - { - mLineList.push_back(Line(text, x, y)); - } - - void clearText() { mLineList.clear(); } - -public: - LLDebugText(LLViewerWindow* window) : mWindow(window) {} - - void update() - { - static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic") ; - - std::string wind_vel_text; - std::string wind_vector_text; - std::string rwind_vel_text; - std::string rwind_vector_text; - std::string audio_text; - - static const std::string beacon_particle = LLTrans::getString("BeaconParticle"); - static const std::string beacon_physical = LLTrans::getString("BeaconPhysical"); - static const std::string beacon_scripted = LLTrans::getString("BeaconScripted"); - static const std::string beacon_scripted_touch = LLTrans::getString("BeaconScriptedTouch"); - static const std::string beacon_sound = LLTrans::getString("BeaconSound"); - static const std::string beacon_media = LLTrans::getString("BeaconMedia"); - static const std::string particle_hiding = LLTrans::getString("ParticleHiding"); - - // Draw the statistics in a light gray - // and in a thin font - mTextColor = LLColor4( 0.86f, 0.86f, 0.86f, 1.f ); - - // Draw stuff growing up from right lower corner of screen - U32 xpos = mWindow->getWindowWidthScaled() - 350; - U32 ypos = 64; - const U32 y_inc = 20; - - clearText(); - - if (gSavedSettings.getBOOL("DebugShowTime")) - { - const U32 y_inc2 = 15; - for (std::map<S32,LLFrameTimer>::reverse_iterator iter = gDebugTimers.rbegin(); - iter != gDebugTimers.rend(); ++iter) - { - S32 idx = iter->first; - LLFrameTimer& timer = iter->second; - F32 time = timer.getElapsedTimeF32(); - S32 hours = (S32)(time / (60*60)); - S32 mins = (S32)((time - hours*(60*60)) / 60); - S32 secs = (S32)((time - hours*(60*60) - mins*60)); - std::string label = gDebugTimerLabel[idx]; - if (label.empty()) label = llformat("Debug: %d", idx); - addText(xpos, ypos, llformat(" %s: %d:%02d:%02d", label.c_str(), hours,mins,secs)); ypos += y_inc2; - } - - F32 time = gFrameTimeSeconds; - S32 hours = (S32)(time / (60*60)); - S32 mins = (S32)((time - hours*(60*60)) / 60); - S32 secs = (S32)((time - hours*(60*60) - mins*60)); - addText(xpos, ypos, llformat("Time: %d:%02d:%02d", hours,mins,secs)); ypos += y_inc; - } - -#if LL_WINDOWS - if (gSavedSettings.getBOOL("DebugShowMemory")) - { - addText(xpos, ypos, llformat("Memory: %d (KB)", LLMemory::getWorkingSetSize() / 1024)); - ypos += y_inc; - } -#endif - - if (gDisplayCameraPos) - { - std::string camera_view_text; - std::string camera_center_text; - std::string agent_view_text; - std::string agent_left_text; - std::string agent_center_text; - std::string agent_root_center_text; - - LLVector3d tvector; // Temporary vector to hold data for printing. - - // Update camera center, camera view, wind info every other frame - tvector = gAgent.getPositionGlobal(); - agent_center_text = llformat("AgentCenter %f %f %f", - (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ])); - - if (isAgentAvatarValid()) - { - tvector = gAgent.getPosGlobalFromAgent(gAgentAvatarp->mRoot.getWorldPosition()); - agent_root_center_text = llformat("AgentRootCenter %f %f %f", - (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ])); - } - else - { - agent_root_center_text = "---"; - } - - - tvector = LLVector4(gAgent.getFrameAgent().getAtAxis()); - agent_view_text = llformat("AgentAtAxis %f %f %f", - (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ])); - - tvector = LLVector4(gAgent.getFrameAgent().getLeftAxis()); - agent_left_text = llformat("AgentLeftAxis %f %f %f", - (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ])); - - tvector = gAgentCamera.getCameraPositionGlobal(); - camera_center_text = llformat("CameraCenter %f %f %f", - (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ])); - - tvector = LLVector4(LLViewerCamera::getInstance()->getAtAxis()); - camera_view_text = llformat("CameraAtAxis %f %f %f", - (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ])); - - addText(xpos, ypos, agent_center_text); ypos += y_inc; - addText(xpos, ypos, agent_root_center_text); ypos += y_inc; - addText(xpos, ypos, agent_view_text); ypos += y_inc; - addText(xpos, ypos, agent_left_text); ypos += y_inc; - addText(xpos, ypos, camera_center_text); ypos += y_inc; - addText(xpos, ypos, camera_view_text); ypos += y_inc; - } - - if (gDisplayWindInfo) - { - wind_vel_text = llformat("Wind velocity %.2f m/s", gWindVec.magVec()); - wind_vector_text = llformat("Wind vector %.2f %.2f %.2f", gWindVec.mV[0], gWindVec.mV[1], gWindVec.mV[2]); - rwind_vel_text = llformat("RWind vel %.2f m/s", gRelativeWindVec.magVec()); - rwind_vector_text = llformat("RWind vec %.2f %.2f %.2f", gRelativeWindVec.mV[0], gRelativeWindVec.mV[1], gRelativeWindVec.mV[2]); - - addText(xpos, ypos, wind_vel_text); ypos += y_inc; - addText(xpos, ypos, wind_vector_text); ypos += y_inc; - addText(xpos, ypos, rwind_vel_text); ypos += y_inc; - addText(xpos, ypos, rwind_vector_text); ypos += y_inc; - } - if (gDisplayWindInfo) - { - if (gAudiop) - { - audio_text= llformat("Audio for wind: %d", gAudiop->isWindEnabled()); - } - addText(xpos, ypos, audio_text); ypos += y_inc; - } - if (gDisplayFOV) - { - addText(xpos, ypos, llformat("FOV: %2.1f deg", RAD_TO_DEG * LLViewerCamera::getInstance()->getView())); - ypos += y_inc; - } - if (gDisplayBadge) - { - addText(xpos, ypos+(y_inc/2), llformat("Hippos!", RAD_TO_DEG * LLViewerCamera::getInstance()->getView())); - ypos += y_inc * 2; - } - - /*if (LLViewerJoystick::getInstance()->getOverrideCamera()) - { - addText(xpos + 200, ypos, llformat("Flycam")); - ypos += y_inc; - }*/ - - if (gSavedSettings.getBOOL("DebugShowRenderInfo")) - { - if (gPipeline.getUseVertexShaders() == 0) - { - addText(xpos, ypos, "Shaders Disabled"); - ypos += y_inc; - } - addText(xpos, ypos, llformat("%d MB Vertex Data", LLVertexBuffer::sAllocatedBytes/(1024*1024))); - ypos += y_inc; - - addText(xpos, ypos, llformat("%d Vertex Buffers", LLVertexBuffer::sGLCount)); - ypos += y_inc; - - addText(xpos, ypos, llformat("%d Mapped Buffers", LLVertexBuffer::sMappedCount)); - ypos += y_inc; - - addText(xpos, ypos, llformat("%d Vertex Buffer Binds", LLVertexBuffer::sBindCount)); - ypos += y_inc; - - addText(xpos, ypos, llformat("%d Vertex Buffer Sets", LLVertexBuffer::sSetCount)); - ypos += y_inc; - - addText(xpos, ypos, llformat("%d Texture Binds", LLImageGL::sBindCount)); - ypos += y_inc; - - addText(xpos, ypos, llformat("%d Unique Textures", LLImageGL::sUniqueCount)); - ypos += y_inc; - - addText(xpos, ypos, llformat("%d Render Calls", gPipeline.mBatchCount)); - ypos += y_inc; - - addText(xpos, ypos, llformat("%d Matrix Ops", gPipeline.mMatrixOpCount)); - ypos += y_inc; - - addText(xpos, ypos, llformat("%d Texture Matrix Ops", gPipeline.mTextureMatrixOps)); - ypos += y_inc; - - gPipeline.mTextureMatrixOps = 0; - gPipeline.mMatrixOpCount = 0; - - if (gPipeline.mBatchCount > 0) - { - addText(xpos, ypos, llformat("Batch min/max/mean: %d/%d/%d", gPipeline.mMinBatchSize, gPipeline.mMaxBatchSize, - gPipeline.mTrianglesDrawn/gPipeline.mBatchCount)); - - gPipeline.mMinBatchSize = gPipeline.mMaxBatchSize; - gPipeline.mMaxBatchSize = 0; - gPipeline.mBatchCount = 0; - } - ypos += y_inc; - - addText(xpos, ypos, llformat("UI Verts/Calls: %d/%d", LLRender::sUIVerts, LLRender::sUICalls)); - LLRender::sUICalls = LLRender::sUIVerts = 0; - ypos += y_inc; - - addText(xpos,ypos, llformat("%d/%d Nodes visible", gPipeline.mNumVisibleNodes, LLSpatialGroup::sNodeCount)); - - ypos += y_inc; - - - addText(xpos,ypos, llformat("%d Avatars visible", LLVOAvatar::sNumVisibleAvatars)); - - ypos += y_inc; - - addText(xpos,ypos, llformat("%d Lights visible", LLPipeline::sVisibleLightCount)); - - ypos += y_inc; - - LLVertexBuffer::sBindCount = LLImageGL::sBindCount = - LLVertexBuffer::sSetCount = LLImageGL::sUniqueCount = - gPipeline.mNumVisibleNodes = LLPipeline::sVisibleLightCount = 0; - } - if (gSavedSettings.getBOOL("DebugShowRenderMatrices")) - { - addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[12], gGLProjection[13], gGLProjection[14], gGLProjection[15])); - ypos += y_inc; - - addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[8], gGLProjection[9], gGLProjection[10], gGLProjection[11])); - ypos += y_inc; - - addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[4], gGLProjection[5], gGLProjection[6], gGLProjection[7])); - ypos += y_inc; - - addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[0], gGLProjection[1], gGLProjection[2], gGLProjection[3])); - ypos += y_inc; - - addText(xpos, ypos, "Projection Matrix"); - ypos += y_inc; - - - addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[12], gGLModelView[13], gGLModelView[14], gGLModelView[15])); - ypos += y_inc; - - addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[8], gGLModelView[9], gGLModelView[10], gGLModelView[11])); - ypos += y_inc; - - addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[4], gGLModelView[5], gGLModelView[6], gGLModelView[7])); - ypos += y_inc; - - addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[0], gGLModelView[1], gGLModelView[2], gGLModelView[3])); - ypos += y_inc; - - addText(xpos, ypos, "View Matrix"); - ypos += y_inc; - } - if (gSavedSettings.getBOOL("DebugShowColor")) - { - U8 color[4]; - LLCoordGL coord = gViewerWindow->getCurrentMouse(); - glReadPixels(coord.mX, coord.mY, 1,1,GL_RGBA, GL_UNSIGNED_BYTE, color); - addText(xpos, ypos, llformat("%d %d %d %d", color[0], color[1], color[2], color[3])); - ypos += y_inc; - } - // only display these messages if we are actually rendering beacons at this moment - if (LLPipeline::getRenderBeacons(NULL) && LLFloaterReg::instanceVisible("beacons")) - { - if (LLPipeline::getRenderParticleBeacons(NULL)) - { - addText(xpos, ypos, beacon_particle); - ypos += y_inc; - } - if (LLPipeline::toggleRenderTypeControlNegated((void*)LLPipeline::RENDER_TYPE_PARTICLES)) - { - addText(xpos, ypos, particle_hiding); - ypos += y_inc; - } - if (LLPipeline::getRenderPhysicalBeacons(NULL)) - { - addText(xpos, ypos, beacon_physical); - ypos += y_inc; - } - if (LLPipeline::getRenderScriptedBeacons(NULL)) - { - addText(xpos, ypos, beacon_scripted); - ypos += y_inc; - } - else - if (LLPipeline::getRenderScriptedTouchBeacons(NULL)) - { - addText(xpos, ypos, beacon_scripted_touch); - ypos += y_inc; - } - if (LLPipeline::getRenderSoundBeacons(NULL)) - { - addText(xpos, ypos, beacon_sound); - ypos += y_inc; - } - } - if(log_texture_traffic) - { - U32 old_y = ypos ; - for(S32 i = LLViewerTexture::BOOST_NONE; i < LLViewerTexture::MAX_GL_IMAGE_CATEGORY; i++) - { - if(gTotalTextureBytesPerBoostLevel[i] > 0) - { - addText(xpos, ypos, llformat("Boost_Level %d: %.3f MB", i, (F32)gTotalTextureBytesPerBoostLevel[i] / (1024 * 1024))); - ypos += y_inc; - } - } - if(ypos != old_y) - { - addText(xpos, ypos, "Network traffic for textures:"); - ypos += y_inc; - } - } - - if (gSavedSettings.getBOOL("DebugShowTextureInfo")) - { - LLViewerObject* objectp = NULL ; - //objectp = = gAgentCamera.getFocusObject(); - - LLSelectNode* nodep = LLSelectMgr::instance().getHoverNode(); - if (nodep) - { - objectp = nodep->getObject(); - } - if (objectp && !objectp->isDead()) - { - S32 num_faces = objectp->mDrawable->getNumFaces() ; - - for(S32 i = 0 ; i < num_faces; i++) - { - LLFace* facep = objectp->mDrawable->getFace(i) ; - if(facep) - { - //addText(xpos, ypos, llformat("ts_min: %.3f ts_max: %.3f tt_min: %.3f tt_max: %.3f", facep->mTexExtents[0].mV[0], facep->mTexExtents[1].mV[0], - // facep->mTexExtents[0].mV[1], facep->mTexExtents[1].mV[1])); - //ypos += y_inc; - - addText(xpos, ypos, llformat("v_size: %.3f: p_size: %.3f", facep->getVirtualSize(), facep->getPixelArea())); - ypos += y_inc; - - //const LLTextureEntry *tep = facep->getTextureEntry(); - //if(tep) - //{ - // addText(xpos, ypos, llformat("scale_s: %.3f: scale_t: %.3f", tep->mScaleS, tep->mScaleT)) ; - // ypos += y_inc; - //} - - LLViewerTexture* tex = facep->getTexture() ; - if(tex) - { - addText(xpos, ypos, llformat("ID: %s v_size: %.3f", tex->getID().asString().c_str(), tex->getMaxVirtualSize())); - ypos += y_inc; - } - } - } - } - } - } - - void draw() - { - for (line_list_t::iterator iter = mLineList.begin(); - iter != mLineList.end(); ++iter) - { - const Line& line = *iter; - LLFontGL::getFontMonospace()->renderUTF8(line.text, 0, (F32)line.x, (F32)line.y, mTextColor, - LLFontGL::LEFT, LLFontGL::TOP, - LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE); - } - mLineList.clear(); - } - -}; - -void LLViewerWindow::updateDebugText() -{ - mDebugText->update(); -} - -//////////////////////////////////////////////////////////////////////////// -// -// LLViewerWindow -// - -BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down) -{ - const char* buttonname = ""; - const char* buttonstatestr = ""; - S32 x = pos.mX; - S32 y = pos.mY; - x = llround((F32)x / mDisplayScale.mV[VX]); - y = llround((F32)y / mDisplayScale.mV[VY]); - - // only send mouse clicks to UI if UI is visible - if(gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) - { - - if (down) - { - buttonstatestr = "down" ; - } - else - { - buttonstatestr = "up" ; - } - - switch (clicktype) - { - case LLMouseHandler::CLICK_LEFT: - mLeftMouseDown = down; - buttonname = "Left"; - break; - case LLMouseHandler::CLICK_RIGHT: - mRightMouseDown = down; - buttonname = "Right"; - break; - case LLMouseHandler::CLICK_MIDDLE: - mMiddleMouseDown = down; - buttonname = "Middle"; - break; - case LLMouseHandler::CLICK_DOUBLELEFT: - mLeftMouseDown = down; - buttonname = "Left Double Click"; - break; - } - - LLView::sMouseHandlerMessage.clear(); - - if (gMenuBarView) - { - // stop ALT-key access to menu - gMenuBarView->resetMenuTrigger(); - } - - if (gDebugClicks) - { - llinfos << "ViewerWindow " << buttonname << " mouse " << buttonstatestr << " at " << x << "," << y << llendl; - } - - // Make sure we get a corresponding mouseup event, even if the mouse leaves the window - if (down) - mWindow->captureMouse(); - else - mWindow->releaseMouse(); - - // Indicate mouse was active - LLUI::resetMouseIdleTimer(); - - // Don't let the user move the mouse out of the window until mouse up. - if( LLToolMgr::getInstance()->getCurrentTool()->clipMouseWhenDown() ) - { - mWindow->setMouseClipping(down); - } - - LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture(); - if( mouse_captor ) - { - S32 local_x; - S32 local_y; - mouse_captor->screenPointToLocal( x, y, &local_x, &local_y ); - if (LLView::sDebugMouseHandling) - { - llinfos << buttonname << " Mouse " << buttonstatestr << " handled by captor " << mouse_captor->getName() << llendl; - } - return mouse_captor->handleAnyMouseClick(local_x, local_y, mask, clicktype, down); - } - - // Topmost view gets a chance before the hierarchy - //LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); - //if (top_ctrl) - //{ - // S32 local_x, local_y; - // top_ctrl->screenPointToLocal( x, y, &local_x, &local_y ); - // if (top_ctrl->pointInView(local_x, local_y)) - // { - // return top_ctrl->handleAnyMouseClick(local_x, local_y, mask, clicktype, down) ; - // } - // else - // { - // if (down) - // { - // gFocusMgr.setTopCtrl(NULL); - // } - // } - //} - - // Give the UI views a chance to process the click - if( mRootView->handleAnyMouseClick(x, y, mask, clicktype, down) ) - { - if (LLView::sDebugMouseHandling) - { - llinfos << buttonname << " Mouse " << buttonstatestr << " " << LLView::sMouseHandlerMessage << llendl; - } - return TRUE; - } - else if (LLView::sDebugMouseHandling) - { - llinfos << buttonname << " Mouse " << buttonstatestr << " not handled by view" << llendl; - } - } - - // Do not allow tool manager to handle mouseclicks if we have disconnected - if(!gDisconnected && LLToolMgr::getInstance()->getCurrentTool()->handleAnyMouseClick( x, y, mask, clicktype, down ) ) - { - return TRUE; - } - - - // If we got this far on a down-click, it wasn't handled. - // Up-clicks, though, are always handled as far as the OS is concerned. - BOOL default_rtn = !down; - return default_rtn; -} - -BOOL LLViewerWindow::handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask) -{ - BOOL down = TRUE; - return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down); -} - -BOOL LLViewerWindow::handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK mask) -{ - // try handling as a double-click first, then a single-click if that - // wasn't handled. - BOOL down = TRUE; - if (handleAnyMouseClick(window, pos, mask, - LLMouseHandler::CLICK_DOUBLELEFT, down)) - { - return TRUE; - } - return handleMouseDown(window, pos, mask); -} - -BOOL LLViewerWindow::handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) -{ - BOOL down = FALSE; - return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down); -} - - -BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK mask) -{ - S32 x = pos.mX; - S32 y = pos.mY; - x = llround((F32)x / mDisplayScale.mV[VX]); - y = llround((F32)y / mDisplayScale.mV[VY]); - - BOOL down = TRUE; - BOOL handle = handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down); - if (handle) - return handle; - - // *HACK: this should be rolled into the composite tool logic, not - // hardcoded at the top level. - if (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance()) - { - // If the current tool didn't process the click, we should show - // the pie menu. This can be done by passing the event to the pie - // menu tool. - LLToolPie::getInstance()->handleRightMouseDown(x, y, mask); - // show_context_menu( x, y, mask ); - } - - return TRUE; -} - -BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) -{ - BOOL down = FALSE; - return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down); -} - -BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask) -{ - BOOL down = TRUE; - LLVoiceClient::getInstance()->middleMouseState(true); - handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down); - - // Always handled as far as the OS is concerned. - return TRUE; -} - -LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *window, LLCoordGL pos, MASK mask, LLWindowCallbacks::DragNDropAction action, std::string data) -{ - LLWindowCallbacks::DragNDropResult result = LLWindowCallbacks::DND_NONE; - - const bool prim_media_dnd_enabled = gSavedSettings.getBOOL("PrimMediaDragNDrop"); - const bool slurl_dnd_enabled = gSavedSettings.getBOOL("SLURLDragNDrop"); - - if ( prim_media_dnd_enabled || slurl_dnd_enabled ) - { - switch(action) - { - // Much of the handling for these two cases is the same. - case LLWindowCallbacks::DNDA_TRACK: - case LLWindowCallbacks::DNDA_DROPPED: - case LLWindowCallbacks::DNDA_START_TRACKING: - { - bool drop = (LLWindowCallbacks::DNDA_DROPPED == action); - - if (slurl_dnd_enabled) - { - LLSLURL dropped_slurl(data); - if(dropped_slurl.isSpatial()) - { - if (drop) - { - LLURLDispatcher::dispatch( dropped_slurl.getSLURLString(), NULL, true ); - return LLWindowCallbacks::DND_MOVE; - } - return LLWindowCallbacks::DND_COPY; - } - } - - if (prim_media_dnd_enabled) - { - LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY, TRUE /*BOOL pick_transparent*/ ); - - LLUUID object_id = pick_info.getObjectID(); - S32 object_face = pick_info.mObjectFace; - std::string url = data; - - lldebugs << "Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << llendl; - - LLVOVolume *obj = dynamic_cast<LLVOVolume*>(static_cast<LLViewerObject*>(pick_info.getObject())); - - if (obj && !obj->getRegion()->getCapability("ObjectMedia").empty()) - { - LLTextureEntry *te = obj->getTE(object_face); - - // can modify URL if we can modify the object or we have navigate permissions - bool allow_modify_url = obj->permModify() || obj->hasMediaPermission( te->getMediaData(), LLVOVolume::MEDIA_PERM_INTERACT ); - - if (te && allow_modify_url ) - { - if (drop) - { - // object does NOT have media already - if ( ! te->hasMedia() ) - { - // we are allowed to modify the object - if ( obj->permModify() ) - { - // Create new media entry - LLSD media_data; - // XXX Should we really do Home URL too? - media_data[LLMediaEntry::HOME_URL_KEY] = url; - media_data[LLMediaEntry::CURRENT_URL_KEY] = url; - media_data[LLMediaEntry::AUTO_PLAY_KEY] = true; - obj->syncMediaData(object_face, media_data, true, true); - // XXX This shouldn't be necessary, should it ?!? - if (obj->getMediaImpl(object_face)) - obj->getMediaImpl(object_face)->navigateReload(); - obj->sendMediaDataUpdate(); - - result = LLWindowCallbacks::DND_COPY; - } - } - else - // object HAS media already - { - // URL passes the whitelist - if (te->getMediaData()->checkCandidateUrl( url ) ) - { - // just navigate to the URL - if (obj->getMediaImpl(object_face)) - { - obj->getMediaImpl(object_face)->navigateTo(url); - } - else - { - // This is very strange. Navigation should - // happen via the Impl, but we don't have one. - // This sends it to the server, which /should/ - // trigger us getting it. Hopefully. - LLSD media_data; - media_data[LLMediaEntry::CURRENT_URL_KEY] = url; - obj->syncMediaData(object_face, media_data, true, true); - obj->sendMediaDataUpdate(); - } - result = LLWindowCallbacks::DND_LINK; - - } - } - LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject); - mDragHoveredObject = NULL; - - } - else - { - // Check the whitelist, if there's media (otherwise just show it) - if (te->getMediaData() == NULL || te->getMediaData()->checkCandidateUrl(url)) - { - if ( obj != mDragHoveredObject) - { - // Highlight the dragged object - LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject); - mDragHoveredObject = obj; - LLSelectMgr::getInstance()->highlightObjectOnly(mDragHoveredObject); - } - result = (! te->hasMedia()) ? LLWindowCallbacks::DND_COPY : LLWindowCallbacks::DND_LINK; - - } - } - } - } - } - } - break; - - case LLWindowCallbacks::DNDA_STOP_TRACKING: - // The cleanup case below will make sure things are unhilighted if necessary. - break; - } - - if (prim_media_dnd_enabled && - result == LLWindowCallbacks::DND_NONE && !mDragHoveredObject.isNull()) - { - LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject); - mDragHoveredObject = NULL; - } - } - - return result; -} - -BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) -{ - BOOL down = FALSE; - LLVoiceClient::getInstance()->middleMouseState(false); - handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down); - - // Always handled as far as the OS is concerned. - return TRUE; -} - -// WARNING: this is potentially called multiple times per frame -void LLViewerWindow::handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask) -{ - S32 x = pos.mX; - S32 y = pos.mY; - - x = llround((F32)x / mDisplayScale.mV[VX]); - y = llround((F32)y / mDisplayScale.mV[VY]); - - mMouseInWindow = TRUE; - - // Save mouse point for access during idle() and display() - - LLCoordGL mouse_point(x, y); - - if (mouse_point != mCurrentMousePoint) - { - LLUI::resetMouseIdleTimer(); - } - - saveLastMouse(mouse_point); - - mWindow->showCursorFromMouseMove(); - - if (gAwayTimer.getElapsedTimeF32() > MIN_AFK_TIME) - { - gAgent.clearAFK(); - } -} - -void LLViewerWindow::handleMouseLeave(LLWindow *window) -{ - // Note: we won't get this if we have captured the mouse. - llassert( gFocusMgr.getMouseCapture() == NULL ); - mMouseInWindow = FALSE; - LLToolTipMgr::instance().blockToolTips(); -} - -BOOL LLViewerWindow::handleCloseRequest(LLWindow *window) -{ - // User has indicated they want to close, but we may need to ask - // about modified documents. - LLAppViewer::instance()->userQuit(); - // Don't quit immediately - return FALSE; -} - -void LLViewerWindow::handleQuit(LLWindow *window) -{ - LLAppViewer::instance()->forceQuit(); -} - -void LLViewerWindow::handleResize(LLWindow *window, S32 width, S32 height) -{ - reshape(width, height); - mResDirty = true; -} - -// The top-level window has gained focus (e.g. via ALT-TAB) -void LLViewerWindow::handleFocus(LLWindow *window) -{ - gFocusMgr.setAppHasFocus(TRUE); - LLModalDialog::onAppFocusGained(); - - gAgent.onAppFocusGained(); - LLToolMgr::getInstance()->onAppFocusGained(); - - // See if we're coming in with modifier keys held down - if (gKeyboard) - { - gKeyboard->resetMaskKeys(); - } - - // resume foreground running timer - // since we artifically limit framerate when not frontmost - gForegroundTime.unpause(); -} - -// The top-level window has lost focus (e.g. via ALT-TAB) -void LLViewerWindow::handleFocusLost(LLWindow *window) -{ - gFocusMgr.setAppHasFocus(FALSE); - //LLModalDialog::onAppFocusLost(); - LLToolMgr::getInstance()->onAppFocusLost(); - gFocusMgr.setMouseCapture( NULL ); - - if (gMenuBarView) - { - // stop ALT-key access to menu - gMenuBarView->resetMenuTrigger(); - } - - // restore mouse cursor - showCursor(); - getWindow()->setMouseClipping(FALSE); - - // If losing focus while keys are down, reset them. - if (gKeyboard) - { - gKeyboard->resetKeys(); - } - - // pause timer that tracks total foreground running time - gForegroundTime.pause(); -} - - -BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated) -{ - // Let the voice chat code check for its PTT key. Note that this never affects event processing. - LLVoiceClient::getInstance()->keyDown(key, mask); - - if (gAwayTimer.getElapsedTimeF32() > MIN_AFK_TIME) - { - gAgent.clearAFK(); - } - - // *NOTE: We want to interpret KEY_RETURN later when it arrives as - // a Unicode char, not as a keydown. Otherwise when client frame - // rate is really low, hitting return sends your chat text before - // it's all entered/processed. - if (key == KEY_RETURN && mask == MASK_NONE) - { - return FALSE; - } - - return gViewerKeyboard.handleKey(key, mask, repeated); -} - -BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key, MASK mask) -{ - // Let the voice chat code check for its PTT key. Note that this never affects event processing. - LLVoiceClient::getInstance()->keyUp(key, mask); - - return FALSE; -} - - -void LLViewerWindow::handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) -{ - LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true); - return gViewerKeyboard.scanKey(key, key_down, key_up, key_level); -} - - - - -BOOL LLViewerWindow::handleActivate(LLWindow *window, BOOL activated) -{ - if (activated) - { - mActive = TRUE; - send_agent_resume(); - gAgent.clearAFK(); - - // Unmute audio - audio_update_volume(); - } - else - { - mActive = FALSE; - - if (gSavedSettings.getS32("AFKTimeout")) - { - gAgent.setAFK(); - } - - // SL-53351: Make sure we're not in mouselook when minimised, to prevent control issues - if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK) - { - gAgentCamera.changeCameraToDefault(); - } - - send_agent_pause(); - - // Mute audio - audio_update_volume(); - } - return TRUE; -} - -BOOL LLViewerWindow::handleActivateApp(LLWindow *window, BOOL activating) -{ - //if (!activating) gAgentCamera.changeCameraToDefault(); - - LLViewerJoystick::getInstance()->setNeedsReset(true); - return FALSE; -} - - -void LLViewerWindow::handleMenuSelect(LLWindow *window, S32 menu_item) -{ -} - - -BOOL LLViewerWindow::handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S32 height) -{ -#if LL_WINDOWS - if (gNoRender) - { - HWND window_handle = (HWND)window->getPlatformWindow(); - PAINTSTRUCT ps; - HDC hdc; - - RECT wnd_rect; - wnd_rect.left = 0; - wnd_rect.top = 0; - wnd_rect.bottom = 200; - wnd_rect.right = 500; - - hdc = BeginPaint(window_handle, &ps); - //SetBKColor(hdc, RGB(255, 255, 255)); - FillRect(hdc, &wnd_rect, CreateSolidBrush(RGB(255, 255, 255))); - - std::string temp_str; - temp_str = llformat( "FPS %3.1f Phy FPS %2.1f Time Dil %1.3f", /* Flawfinder: ignore */ - LLViewerStats::getInstance()->mFPSStat.getMeanPerSec(), - LLViewerStats::getInstance()->mSimPhysicsFPS.getPrev(0), - LLViewerStats::getInstance()->mSimTimeDilation.getPrev(0)); - S32 len = temp_str.length(); - TextOutA(hdc, 0, 0, temp_str.c_str(), len); - - - LLVector3d pos_global = gAgent.getPositionGlobal(); - temp_str = llformat( "Avatar pos %6.1lf %6.1lf %6.1lf", pos_global.mdV[0], pos_global.mdV[1], pos_global.mdV[2]); - len = temp_str.length(); - TextOutA(hdc, 0, 25, temp_str.c_str(), len); - - TextOutA(hdc, 0, 50, "Set \"DisableRendering FALSE\" in settings.ini file to reenable", 61); - EndPaint(window_handle, &ps); - return TRUE; - } -#endif - return FALSE; -} - - -void LLViewerWindow::handleScrollWheel(LLWindow *window, S32 clicks) -{ - handleScrollWheel( clicks ); -} - -void LLViewerWindow::handleWindowBlock(LLWindow *window) -{ - send_agent_pause(); -} - -void LLViewerWindow::handleWindowUnblock(LLWindow *window) -{ - send_agent_resume(); -} - -void LLViewerWindow::handleDataCopy(LLWindow *window, S32 data_type, void *data) -{ - const S32 SLURL_MESSAGE_TYPE = 0; - switch (data_type) - { - case SLURL_MESSAGE_TYPE: - // received URL - std::string url = (const char*)data; - LLMediaCtrl* web = NULL; - const bool trusted_browser = false; - if (LLURLDispatcher::dispatch(url, web, trusted_browser)) - { - // bring window to foreground, as it has just been "launched" from a URL - mWindow->bringToFront(); - } - break; - } -} - -BOOL LLViewerWindow::handleTimerEvent(LLWindow *window) -{ - if (LLViewerJoystick::getInstance()->getOverrideCamera()) - { - LLViewerJoystick::getInstance()->updateStatus(); - return TRUE; - } - return FALSE; -} - -BOOL LLViewerWindow::handleDeviceChange(LLWindow *window) -{ - // give a chance to use a joystick after startup (hot-plugging) - if (!LLViewerJoystick::getInstance()->isJoystickInitialized() ) - { - LLViewerJoystick::getInstance()->init(true); - return TRUE; - } - return FALSE; -} - -void LLViewerWindow::handlePingWatchdog(LLWindow *window, const char * msg) -{ - LLAppViewer::instance()->pingMainloopTimeout(msg); -} - - -void LLViewerWindow::handleResumeWatchdog(LLWindow *window) -{ - LLAppViewer::instance()->resumeMainloopTimeout(); -} - -void LLViewerWindow::handlePauseWatchdog(LLWindow *window) -{ - LLAppViewer::instance()->pauseMainloopTimeout(); -} - -//virtual -std::string LLViewerWindow::translateString(const char* tag) -{ - return LLTrans::getString( std::string(tag) ); -} - -//virtual -std::string LLViewerWindow::translateString(const char* tag, - const std::map<std::string, std::string>& args) -{ - // LLTrans uses a special subclass of std::string for format maps, - // but we must use std::map<> in these callbacks, otherwise we create - // a dependency between LLWindow and LLFormatMapString. So copy the data. - LLStringUtil::format_map_t args_copy; - std::map<std::string,std::string>::const_iterator it = args.begin(); - for ( ; it != args.end(); ++it) - { - args_copy[it->first] = it->second; - } - return LLTrans::getString( std::string(tag), args_copy); -} - -// -// Classes -// -LLViewerWindow::LLViewerWindow( - const std::string& title, const std::string& name, - S32 x, S32 y, - S32 width, S32 height, - BOOL fullscreen, BOOL ignore_pixel_depth) // fullscreen is no longer used - : - mWindow(NULL), - mActive(TRUE), - mWindowRectRaw(0, height, width, 0), - mWindowRectScaled(0, height, width, 0), - mWorldViewRectRaw(0, height, width, 0), - mLeftMouseDown(FALSE), - mMiddleMouseDown(FALSE), - mRightMouseDown(FALSE), - mMouseInWindow( FALSE ), - mLastMask( MASK_NONE ), - mToolStored( NULL ), - mHideCursorPermanent( FALSE ), - mCursorHidden(FALSE), - mIgnoreActivate( FALSE ), - mResDirty(false), - mStatesDirty(false), - mCurrResolutionIndex(0), - mViewerWindowListener(new LLViewerWindowListener(this)), - mProgressView(NULL) -{ - LLNotificationChannel::buildChannel("VW_alerts", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "alert")); - LLNotificationChannel::buildChannel("VW_alertmodal", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "alertmodal")); - - LLNotifications::instance().getChannel("VW_alerts")->connectChanged(&LLViewerWindow::onAlert); - LLNotifications::instance().getChannel("VW_alertmodal")->connectChanged(&LLViewerWindow::onAlert); - LLNotifications::instance().setIgnoreAllNotifications(gSavedSettings.getBOOL("IgnoreAllNotifications")); - llinfos << "NOTE: ALL NOTIFICATIONS THAT OCCUR WILL GET ADDED TO IGNORE LIST FOR LATER RUNS." << llendl; - - // Default to application directory. - LLViewerWindow::sSnapshotBaseName = "Snapshot"; - LLViewerWindow::sMovieBaseName = "SLmovie"; - resetSnapshotLoc(); - - // create window - mWindow = LLWindowManager::createWindow(this, - title, name, x, y, width, height, 0, - fullscreen, - gNoRender, - gSavedSettings.getBOOL("DisableVerticalSync"), - !gNoRender, - ignore_pixel_depth, - gSavedSettings.getBOOL("RenderUseFBO") ? 0 : gSavedSettings.getU32("RenderFSAASamples")); //don't use window level anti-aliasing if FBOs are enabled - - if (!LLAppViewer::instance()->restoreErrorTrap()) - { - LL_WARNS("Window") << " Someone took over my signal/exception handler (post createWindow)!" << LL_ENDL; - } - - LLCoordScreen scr; - mWindow->getSize(&scr); - - if(fullscreen && ( scr.mX!=width || scr.mY!=height)) - { - llwarns << "Fullscreen has forced us in to a different resolution now using "<<scr.mX<<" x "<<scr.mY<<llendl; - gSavedSettings.setS32("FullScreenWidth",scr.mX); - gSavedSettings.setS32("FullScreenHeight",scr.mY); - } - - if (NULL == mWindow) - { - LLSplashScreen::update(LLTrans::getString("ShuttingDown")); -#if LL_LINUX || LL_SOLARIS - llwarns << "Unable to create window, be sure screen is set at 32-bit color and your graphics driver is configured correctly. See README-linux.txt or README-solaris.txt for further information." - << llendl; -#else - LL_WARNS("Window") << "Unable to create window, be sure screen is set at 32-bit color in Control Panels->Display->Settings" - << LL_ENDL; -#endif - LLAppViewer::instance()->fastQuit(1); - } - - // Get the real window rect the window was created with (since there are various OS-dependent reasons why - // the size of a window or fullscreen context may have been adjusted slightly...) - F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor"); - - mDisplayScale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f)); - mDisplayScale *= ui_scale_factor; - LLUI::setScaleFactor(mDisplayScale); - - { - LLCoordWindow size; - mWindow->getSize(&size); - mWindowRectRaw.set(0, size.mY, size.mX, 0); - mWindowRectScaled.set(0, llround((F32)size.mY / mDisplayScale.mV[VY]), llround((F32)size.mX / mDisplayScale.mV[VX]), 0); - } - - LLFontManager::initClass(); - - // - // We want to set this stuff up BEFORE we initialize the pipeline, so we can turn off - // stuff like AGP if we think that it'll crash the viewer. - // - LL_DEBUGS("Window") << "Loading feature tables." << LL_ENDL; - - LLFeatureManager::getInstance()->init(); - - // Initialize OpenGL Renderer - if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderVBOEnable") || - !gGLManager.mHasVertexBufferObject) - { - gSavedSettings.setBOOL("RenderVBOEnable", FALSE); - } - LLVertexBuffer::initClass(gSavedSettings.getBOOL("RenderVBOEnable"), gSavedSettings.getBOOL("RenderVBOMappingDisable")); - - if (LLFeatureManager::getInstance()->isSafe() - || (gSavedSettings.getS32("LastFeatureVersion") != LLFeatureManager::getInstance()->getVersion()) - || (gSavedSettings.getS32("LastGPUClass") != LLFeatureManager::getInstance()->getGPUClass()) - || (gSavedSettings.getBOOL("ProbeHardwareOnStartup"))) - { - LLFeatureManager::getInstance()->applyRecommendedSettings(); - gSavedSettings.setBOOL("ProbeHardwareOnStartup", FALSE); - } - - if (!gGLManager.mHasDepthClamp) - { - LL_INFOS("RenderInit") << "Missing feature GL_ARB_depth_clamp. Void water might disappear in rare cases." << LL_ENDL; - } - - // If we crashed while initializng GL stuff last time, disable certain features - if (gSavedSettings.getBOOL("RenderInitError")) - { - mInitAlert = "DisplaySettingsNoShaders"; - LLFeatureManager::getInstance()->setGraphicsLevel(0, false); - gSavedSettings.setU32("RenderQualityPerformance", 0); - } - - // Init the image list. Must happen after GL is initialized and before the images that - // LLViewerWindow needs are requested. - LLImageGL::initClass(LLViewerTexture::MAX_GL_IMAGE_CATEGORY) ; - gTextureList.init(); - LLViewerTextureManager::init() ; - gBumpImageList.init(); - - // Init font system, but don't actually load the fonts yet - // because our window isn't onscreen and they take several - // seconds to parse. - LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"), - mDisplayScale.mV[VX], - mDisplayScale.mV[VY], - gDirUtilp->getAppRODataDir(), - LLUI::getXUIPaths()); - - // Create container for all sub-views - LLView::Params rvp; - rvp.name("root"); - rvp.rect(mWindowRectScaled); - rvp.mouse_opaque(false); - rvp.follows.flags(FOLLOWS_NONE); - mRootView = LLUICtrlFactory::create<LLRootView>(rvp); - LLUI::setRootView(mRootView); - - // Make avatar head look forward at start - mCurrentMousePoint.mX = getWindowWidthScaled() / 2; - mCurrentMousePoint.mY = getWindowHeightScaled() / 2; - - gShowOverlayTitle = gSavedSettings.getBOOL("ShowOverlayTitle"); - mOverlayTitle = gSavedSettings.getString("OverlayTitle"); - // Can't have spaces in settings.ini strings, so use underscores instead and convert them. - LLStringUtil::replaceChar(mOverlayTitle, '_', ' '); - - // sync the keyboard's setting with the saved setting - gSavedSettings.getControl("NumpadControl")->firePropertyChanged(); - - mDebugText = new LLDebugText(this); - - mWorldViewRectScaled = calcScaledRect(mWorldViewRectRaw, mDisplayScale); -} - -void LLViewerWindow::initGLDefaults() -{ - gGL.setSceneBlendType(LLRender::BT_ALPHA); - glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE ); - - F32 ambient[4] = {0.f,0.f,0.f,0.f }; - F32 diffuse[4] = {1.f,1.f,1.f,1.f }; - glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,ambient); - glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,diffuse); - - glPixelStorei(GL_PACK_ALIGNMENT,1); - glPixelStorei(GL_UNPACK_ALIGNMENT,1); - - gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); - - // lights for objects - glShadeModel( GL_SMOOTH ); - - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); - - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); - - glCullFace(GL_BACK); - - // RN: Need this for translation and stretch manip. - gCone.prerender(); - gBox.prerender(); - gSphere.prerender(); - gCylinder.prerender(); -} - -struct MainPanel : public LLPanel -{ -}; - -void LLViewerWindow::initBase() -{ - S32 height = getWindowHeightScaled(); - S32 width = getWindowWidthScaled(); - - LLRect full_window(0, height, width, 0); - - //////////////////// - // - // Set the gamma - // - - F32 gamma = gSavedSettings.getF32("RenderGamma"); - if (gamma != 0.0f) - { - getWindow()->setGamma(gamma); - } - - // Create global views - - // Create the floater view at the start so that other views can add children to it. - // (But wait to add it as a child of the root view so that it will be in front of the - // other views.) - MainPanel* main_view = new MainPanel(); - main_view->buildFromFile("main_view.xml"); - main_view->setShape(full_window); - getRootView()->addChild(main_view); - - // placeholder widget that controls where "world" is rendered - mWorldViewPlaceholder = main_view->getChildView("world_view_rect")->getHandle(); - mNonSideTrayView = main_view->getChildView("non_side_tray_view")->getHandle(); - mFloaterViewHolder = main_view->getChildView("floater_view_holder")->getHandle(); - mPopupView = main_view->getChild<LLPopupView>("popup_holder"); - mHintHolder = main_view->getChild<LLView>("hint_holder")->getHandle(); - mLoginPanelHolder = main_view->getChild<LLView>("login_panel_holder")->getHandle(); - - // Constrain floaters to inside the menu and status bar regions. - gFloaterView = main_view->getChild<LLFloaterView>("Floater View"); - gFloaterView->setFloaterSnapView(main_view->getChild<LLView>("floater_snap_region")->getHandle()); - gSnapshotFloaterView = main_view->getChild<LLSnapshotFloaterView>("Snapshot Floater View"); - - - // Console - llassert( !gConsole ); - LLConsole::Params cp; - cp.name("console"); - cp.max_lines(gSavedSettings.getS32("ConsoleBufferSize")); - cp.rect(getChatConsoleRect()); - cp.persist_time(gSavedSettings.getF32("ChatPersistTime")); - cp.font_size_index(gSavedSettings.getS32("ChatFontSize")); - cp.follows.flags(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM); - gConsole = LLUICtrlFactory::create<LLConsole>(cp); - getRootView()->addChild(gConsole); - - // optionally forward warnings to chat console/chat floater - // for qa runs and dev builds -#if !LL_RELEASE_FOR_DOWNLOAD - LLError::addRecorder(RecordToChatConsole::getInstance()); -#else - if(gSavedSettings.getBOOL("QAMode")) - { - LLError::addRecorder(RecordToChatConsole::getInstance()); - } -#endif - - gDebugView = getRootView()->getChild<LLDebugView>("DebugView"); - gDebugView->init(); - gToolTipView = getRootView()->getChild<LLToolTipView>("tooltip view"); - - // Initialize busy response message when logged in - LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLFloaterPreference::initBusyResponse)); - - // Add the progress bar view (startup view), which overrides everything - mProgressView = getRootView()->findChild<LLProgressView>("progress_view"); - setShowProgress(FALSE); - setProgressCancelButtonVisible(FALSE); - - gMenuHolder = getRootView()->getChild<LLViewerMenuHolderGL>("Menu Holder"); - - LLMenuGL::sMenuContainer = gMenuHolder; - -} - -void LLViewerWindow::initWorldUI() -{ - S32 height = mRootView->getRect().getHeight(); - S32 width = mRootView->getRect().getWidth(); - LLRect full_window(0, height, width, 0); - - - gIMMgr = LLIMMgr::getInstance(); - - //getRootView()->sendChildToFront(gFloaterView); - //getRootView()->sendChildToFront(gSnapshotFloaterView); - - // new bottom panel - LLPanel* bottom_tray_container = getRootView()->getChild<LLPanel>("bottom_tray_container"); - LLBottomTray* bottom_tray = LLBottomTray::getInstance(); - bottom_tray->setShape(bottom_tray_container->getLocalRect()); - bottom_tray->setFollowsAll(); - bottom_tray_container->addChild(bottom_tray); - bottom_tray_container->setVisible(TRUE); - - LLRect morph_view_rect = full_window; - morph_view_rect.stretch( -STATUS_BAR_HEIGHT ); - morph_view_rect.mTop = full_window.mTop - 32; - LLMorphView::Params mvp; - mvp.name("MorphView"); - mvp.rect(morph_view_rect); - mvp.visible(false); - gMorphView = LLUICtrlFactory::create<LLMorphView>(mvp); - getRootView()->addChild(gMorphView); - - LLWorldMapView::initClass(); - - // Force gFloaterWorldMap to initialize - LLFloaterReg::getInstance("world_map"); - - // Force gFloaterTools to initialize - LLFloaterReg::getInstance("build"); - LLFloaterReg::hideInstance("build"); - - // Status bar - LLPanel* status_bar_container = getRootView()->getChild<LLPanel>("status_bar_container"); - gStatusBar = new LLStatusBar(status_bar_container->getLocalRect()); - gStatusBar->setFollowsAll(); - gStatusBar->setShape(status_bar_container->getLocalRect()); - // sync bg color with menu bar - gStatusBar->setBackgroundColor( gMenuBarView->getBackgroundColor().get() ); - status_bar_container->addChild(gStatusBar); - status_bar_container->setVisible(TRUE); - - // Navigation bar - LLPanel* nav_bar_container = getRootView()->getChild<LLPanel>("nav_bar_container"); - - LLNavigationBar* navbar = LLNavigationBar::getInstance(); - navbar->setShape(nav_bar_container->getLocalRect()); - navbar->setBackgroundColor(gMenuBarView->getBackgroundColor().get()); - nav_bar_container->addChild(navbar); - nav_bar_container->setVisible(TRUE); - - if (!gSavedSettings.getBOOL("ShowNavbarNavigationPanel")) - { - navbar->showNavigationPanel(FALSE); - } - - if (!gSavedSettings.getBOOL("ShowNavbarFavoritesPanel")) - { - navbar->showFavoritesPanel(FALSE); - } - - // Top Info bar - LLPanel* topinfo_bar_container = getRootView()->getChild<LLPanel>("topinfo_bar_container"); - LLPanelTopInfoBar* topinfo_bar = LLPanelTopInfoBar::getInstance(); - - topinfo_bar->setShape(topinfo_bar_container->getLocalRect()); - - topinfo_bar_container->addChild(topinfo_bar); - topinfo_bar_container->setVisible(TRUE); - - if (!gSavedSettings.getBOOL("ShowMiniLocationPanel")) - { - topinfo_bar->setVisible(FALSE); - } - - if ( gHUDView == NULL ) - { - LLRect hud_rect = full_window; - hud_rect.mBottom += 50; - if (gMenuBarView && gMenuBarView->isInVisibleChain()) - { - hud_rect.mTop -= gMenuBarView->getRect().getHeight(); - } - gHUDView = new LLHUDView(hud_rect); - // put behind everything else in the UI - getRootView()->addChildInBack(gHUDView); - } - - LLPanel* panel_ssf_container = getRootView()->getChild<LLPanel>("stand_stop_flying_container"); - LLPanelStandStopFlying* panel_stand_stop_flying = LLPanelStandStopFlying::getInstance(); - panel_ssf_container->addChild(panel_stand_stop_flying); - panel_ssf_container->setVisible(TRUE); - - // put sidetray in container - LLPanel* side_tray_container = getRootView()->getChild<LLPanel>("side_tray_container"); - LLSideTray* sidetrayp = LLSideTray::getInstance(); - sidetrayp->setShape(side_tray_container->getLocalRect()); - // don't follow right edge to avoid spurious resizes, since we are using a fixed width layout - sidetrayp->setFollows(FOLLOWS_LEFT|FOLLOWS_TOP|FOLLOWS_BOTTOM); - side_tray_container->addChild(sidetrayp); - side_tray_container->setVisible(FALSE); - - // put sidetray buttons in their own panel - LLPanel* buttons_panel = sidetrayp->getButtonsPanel(); - LLPanel* buttons_panel_container = getRootView()->getChild<LLPanel>("side_bar_tabs"); - buttons_panel->setShape(buttons_panel_container->getLocalRect()); - buttons_panel->setFollowsAll(); - buttons_panel_container->addChild(buttons_panel); - - LLView* avatar_picker_destination_guide_container = gViewerWindow->getRootView()->getChild<LLView>("avatar_picker_and_destination_guide_container"); - avatar_picker_destination_guide_container->getChild<LLButton>("close")->setCommitCallback(boost::bind(toggle_destination_and_avatar_picker, LLSD())); - LLMediaCtrl* destinations = avatar_picker_destination_guide_container->findChild<LLMediaCtrl>("destination_guide_contents"); - LLMediaCtrl* avatar_picker = avatar_picker_destination_guide_container->findChild<LLMediaCtrl>("avatar_picker_contents"); - if (destinations) - { - destinations->navigateTo(gSavedSettings.getString("DestinationGuideURL"), "text/html"); - } - - if (avatar_picker) - { - avatar_picker->navigateTo(gSavedSettings.getString("AvatarPickerURL"), "text/html"); - } - -} - -// Destroy the UI -void LLViewerWindow::shutdownViews() -{ - // clean up warning logger - LLError::removeRecorder(RecordToChatConsole::getInstance()); - - delete mDebugText; - mDebugText = NULL; - - // Cleanup global views - if (gMorphView) - { - gMorphView->setVisible(FALSE); - } - - // DEV-40930: Clear sModalStack. Otherwise, any LLModalDialog left open - // will crump with LL_ERRS. - LLModalDialog::shutdownModals(); - - // destroy the nav bar, not currently part of gViewerWindow - // *TODO: Make LLNavigationBar part of gViewerWindow - delete LLNavigationBar::getInstance(); - - // destroy menus after instantiating navbar above, as it needs - // access to gMenuHolder - cleanup_menus(); - - // Delete all child views. - delete mRootView; - mRootView = NULL; - - // Automatically deleted as children of mRootView. Fix the globals. - gStatusBar = NULL; - gIMMgr = NULL; - gToolTipView = NULL; - - gFloaterView = NULL; - gMorphView = NULL; - - gHUDView = NULL; -} - -void LLViewerWindow::shutdownGL() -{ - //-------------------------------------------------------- - // Shutdown GL cleanly. Order is very important here. - //-------------------------------------------------------- - LLFontGL::destroyDefaultFonts(); - LLFontManager::cleanupClass(); - stop_glerror(); - - gSky.cleanup(); - stop_glerror(); - - LLWearableList::instance().cleanup() ; - - gTextureList.shutdown(); - stop_glerror(); - - gBumpImageList.shutdown(); - stop_glerror(); - - LLWorldMapView::cleanupTextures(); - - llinfos << "Cleaning up pipeline" << llendl; - gPipeline.cleanup(); - stop_glerror(); - - LLViewerTextureManager::cleanup() ; - LLImageGL::cleanupClass() ; - - llinfos << "All textures and llimagegl images are destroyed!" << llendl ; - - llinfos << "Cleaning up select manager" << llendl; - LLSelectMgr::getInstance()->cleanup(); - - LLVertexBuffer::cleanupClass(); - - llinfos << "Stopping GL during shutdown" << llendl; - if (!gNoRender) - { - stopGL(FALSE); - stop_glerror(); - } - - gGL.shutdown(); -} - -// shutdownViews() and shutdownGL() need to be called first -LLViewerWindow::~LLViewerWindow() -{ - llinfos << "Destroying Window" << llendl; - destroyWindow(); - - delete mDebugText; - mDebugText = NULL; -} - - -void LLViewerWindow::setCursor( ECursorType c ) -{ - mWindow->setCursor( c ); -} - -void LLViewerWindow::showCursor() -{ - mWindow->showCursor(); - - mCursorHidden = FALSE; -} - -void LLViewerWindow::hideCursor() -{ - // And hide the cursor - mWindow->hideCursor(); - - mCursorHidden = TRUE; -} - -void LLViewerWindow::sendShapeToSim() -{ - LLMessageSystem* msg = gMessageSystem; - if(!msg) return; - msg->newMessageFast(_PREHASH_AgentHeightWidth); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addU32Fast(_PREHASH_CircuitCode, gMessageSystem->mOurCircuitCode); - msg->nextBlockFast(_PREHASH_HeightWidthBlock); - msg->addU32Fast(_PREHASH_GenCounter, 0); - U16 height16 = (U16) mWorldViewRectRaw.getHeight(); - U16 width16 = (U16) mWorldViewRectRaw.getWidth(); - msg->addU16Fast(_PREHASH_Height, height16); - msg->addU16Fast(_PREHASH_Width, width16); - gAgent.sendReliableMessage(); -} - -// Must be called after window is created to set up agent -// camera variables and UI variables. -void LLViewerWindow::reshape(S32 width, S32 height) -{ - // Destroying the window at quit time generates spurious - // reshape messages. We don't care about these, and we - // don't want to send messages because the message system - // may have been destructed. - if (!LLApp::isExiting()) - { - if (gNoRender) - { - return; - } - - gWindowResized = TRUE; - - // update our window rectangle - mWindowRectRaw.mRight = mWindowRectRaw.mLeft + width; - mWindowRectRaw.mTop = mWindowRectRaw.mBottom + height; - - //glViewport(0, 0, width, height ); - - if (height > 0) - { - LLViewerCamera::getInstance()->setViewHeightInPixels( mWorldViewRectRaw.getHeight() ); - LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() ); - } - - calcDisplayScale(); - - BOOL display_scale_changed = mDisplayScale != LLUI::sGLScaleFactor; - LLUI::setScaleFactor(mDisplayScale); - - // update our window rectangle - mWindowRectScaled.mRight = mWindowRectScaled.mLeft + llround((F32)width / mDisplayScale.mV[VX]); - mWindowRectScaled.mTop = mWindowRectScaled.mBottom + llround((F32)height / mDisplayScale.mV[VY]); - - setup2DViewport(); - - // Inform lower views of the change - // round up when converting coordinates to make sure there are no gaps at edge of window - LLView::sForceReshape = display_scale_changed; - mRootView->reshape(llceil((F32)width / mDisplayScale.mV[VX]), llceil((F32)height / mDisplayScale.mV[VY])); - LLView::sForceReshape = FALSE; - - // clear font width caches - if (display_scale_changed) - { - LLHUDObject::reshapeAll(); - } - - sendShapeToSim(); - - // store new settings for the mode we are in, regardless - // Only save size if not maximized - BOOL maximized = mWindow->getMaximized(); - gSavedSettings.setBOOL("WindowMaximized", maximized); - - LLCoordScreen window_size; - if (!maximized - && mWindow->getSize(&window_size)) - { - gSavedSettings.setS32("WindowWidth", window_size.mX); - gSavedSettings.setS32("WindowHeight", window_size.mY); - } - - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_WINDOW_WIDTH, (F64)width); - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_WINDOW_HEIGHT, (F64)height); - } -} - - -// Hide normal UI when a logon fails -void LLViewerWindow::setNormalControlsVisible( BOOL visible ) -{ - if(LLBottomTray::instanceExists()) - { - LLBottomTray::getInstance()->setVisible(visible); - LLBottomTray::getInstance()->setEnabled(visible); - } - - if ( gMenuBarView ) - { - gMenuBarView->setVisible( visible ); - gMenuBarView->setEnabled( visible ); - - // ...and set the menu color appropriately. - setMenuBackgroundColor(gAgent.getGodLevel() > GOD_NOT, - LLGridManager::getInstance()->isInProductionGrid()); - } - - if ( gStatusBar ) - { - gStatusBar->setVisible( visible ); - gStatusBar->setEnabled( visible ); - } - - LLNavigationBar* navbarp = LLUI::getRootView()->findChild<LLNavigationBar>("navigation_bar"); - if (navbarp) - { - navbarp->setVisible( visible ); - } -} - -void LLViewerWindow::setMenuBackgroundColor(bool god_mode, bool dev_grid) -{ - LLSD args; - LLColor4 new_bg_color; - - // no l10n problem because channel is always an english string - std::string channel = LLVersionInfo::getChannel(); - bool isProject = (channel.find("Project") != std::string::npos); - - // god more important than project, proj more important than grid - if(god_mode && LLGridManager::getInstance()->isInProductionGrid()) - { - new_bg_color = LLUIColorTable::instance().getColor( "MenuBarGodBgColor" ); - } - else if(god_mode && !LLGridManager::getInstance()->isInProductionGrid()) - { - new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionGodBgColor" ); - } - else if (!god_mode && isProject) - { - new_bg_color = LLUIColorTable::instance().getColor( "MenuBarProjectBgColor" ); - } - else if(!god_mode && !LLGridManager::getInstance()->isInProductionGrid()) - { - new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" ); - } - else - { - new_bg_color = LLUIColorTable::instance().getColor( "MenuBarBgColor" ); - } - - if(gMenuBarView) - { - gMenuBarView->setBackgroundColor( new_bg_color ); - } - - if(gStatusBar) - { - gStatusBar->setBackgroundColor( new_bg_color ); - } -} - -void LLViewerWindow::drawDebugText() -{ - gGL.color4f(1,1,1,1); - gGL.pushMatrix(); - gGL.pushUIMatrix(); - { - // scale view by UI global scale factor and aspect ratio correction factor - gGL.scaleUI(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f); - mDebugText->draw(); - } - gGL.popUIMatrix(); - gGL.popMatrix(); - - gGL.flush(); -} - -void LLViewerWindow::draw() -{ - -//#if LL_DEBUG - LLView::sIsDrawing = TRUE; -//#endif - stop_glerror(); - - LLUI::setLineWidth(1.f); - - LLUI::setLineWidth(1.f); - // Reset any left-over transforms - glMatrixMode(GL_MODELVIEW); - - glLoadIdentity(); - - //S32 screen_x, screen_y; - - if (!gSavedSettings.getBOOL("RenderUIBuffer")) - { - LLUI::sDirtyRect = getWindowRectScaled(); - } - - // HACK for timecode debugging - if (gSavedSettings.getBOOL("DisplayTimecode")) - { - // draw timecode block - std::string text; - - glLoadIdentity(); - - microsecondsToTimecodeString(gFrameTime,text); - const LLFontGL* font = LLFontGL::getFontSansSerif(); - font->renderUTF8(text, 0, - llround((getWindowWidthScaled()/2)-100.f), - llround((getWindowHeightScaled()-60.f)), - LLColor4( 1.f, 1.f, 1.f, 1.f ), - LLFontGL::LEFT, LLFontGL::TOP); - } - - // Draw all nested UI views. - // No translation needed, this view is glued to 0,0 - - gGL.pushMatrix(); - LLUI::pushMatrix(); - { - - // scale view by UI global scale factor and aspect ratio correction factor - gGL.scaleUI(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f); - - LLVector2 old_scale_factor = LLUI::sGLScaleFactor; - // apply camera zoom transform (for high res screenshots) - F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor(); - S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion(); - if (zoom_factor > 1.f) - { - //decompose subregion number to x and y values - int pos_y = sub_region / llceil(zoom_factor); - int pos_x = sub_region - (pos_y*llceil(zoom_factor)); - // offset for this tile - glTranslatef((F32)getWindowWidthScaled() * -(F32)pos_x, - (F32)getWindowHeightScaled() * -(F32)pos_y, - 0.f); - glScalef(zoom_factor, zoom_factor, 1.f); - LLUI::sGLScaleFactor *= zoom_factor; - } - - // Draw tool specific overlay on world - LLToolMgr::getInstance()->getCurrentTool()->draw(); - - if( gAgentCamera.cameraMouselook() || LLFloaterCamera::inFreeCameraMode() ) - { - drawMouselookInstructions(); - stop_glerror(); - } - - // Draw all nested UI views. - // No translation needed, this view is glued to 0,0 - mRootView->draw(); - - if (LLView::sDebugRects) - { - gToolTipView->drawStickyRect(); - } - - // Draw optional on-top-of-everyone view - LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); - if (top_ctrl && top_ctrl->getVisible()) - { - S32 screen_x, screen_y; - top_ctrl->localPointToScreen(0, 0, &screen_x, &screen_y); - - glMatrixMode(GL_MODELVIEW); - LLUI::pushMatrix(); - LLUI::translate( (F32) screen_x, (F32) screen_y, 0.f); - top_ctrl->draw(); - LLUI::popMatrix(); - } - - - if( gShowOverlayTitle && !mOverlayTitle.empty() ) - { - // Used for special titles such as "Second Life - Special E3 2003 Beta" - const S32 DIST_FROM_TOP = 20; - LLFontGL::getFontSansSerifBig()->renderUTF8( - mOverlayTitle, 0, - llround( getWindowWidthScaled() * 0.5f), - getWindowHeightScaled() - DIST_FROM_TOP, - LLColor4(1, 1, 1, 0.4f), - LLFontGL::HCENTER, LLFontGL::TOP); - } - - LLUI::sGLScaleFactor = old_scale_factor; - } - LLUI::popMatrix(); - gGL.popMatrix(); - -//#if LL_DEBUG - LLView::sIsDrawing = FALSE; -//#endif -} - -// Takes a single keydown event, usually when UI is visible -BOOL LLViewerWindow::handleKey(KEY key, MASK mask) -{ - // hide tooltips on keypress - LLToolTipMgr::instance().blockToolTips(); - - if (gFocusMgr.getKeyboardFocus() - && !(mask & (MASK_CONTROL | MASK_ALT)) - && !gFocusMgr.getKeystrokesOnly()) - { - // We have keyboard focus, and it's not an accelerator - if (key < 0x80) - { - // Not a special key, so likely (we hope) to generate a character. Let it fall through to character handler first. - return (gFocusMgr.getKeyboardFocus() != NULL); - } - } - - // let menus handle navigation keys for navigation - if ((gMenuBarView && gMenuBarView->handleKey(key, mask, TRUE)) - ||(gLoginMenuBarView && gLoginMenuBarView->handleKey(key, mask, TRUE)) - ||(gMenuHolder && gMenuHolder->handleKey(key, mask, TRUE))) - { - return TRUE; - } - - LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus(); - - // give menus a chance to handle modified (Ctrl, Alt) shortcut keys before current focus - // as long as focus isn't locked - if (mask & (MASK_CONTROL | MASK_ALT) && !gFocusMgr.focusLocked()) - { - // Check the current floater's menu first, if it has one. - if (gFocusMgr.keyboardFocusHasAccelerators() - && keyboard_focus - && keyboard_focus->handleKey(key,mask,FALSE)) - { - return TRUE; - } - - if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask)) - ||(gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask))) - { - return TRUE; - } - } - - // give floaters first chance to handle TAB key - // so frontmost floater gets focus - // if nothing has focus, go to first or last UI element as appropriate - if (key == KEY_TAB && (mask & MASK_CONTROL || gFocusMgr.getKeyboardFocus() == NULL)) - { - if (gMenuHolder) gMenuHolder->hideMenus(); - - // if CTRL-tabbing (and not just TAB with no focus), go into window cycle mode - gFloaterView->setCycleMode((mask & MASK_CONTROL) != 0); - - // do CTRL-TAB and CTRL-SHIFT-TAB logic - if (mask & MASK_SHIFT) - { - mRootView->focusPrevRoot(); - } - else - { - mRootView->focusNextRoot(); - } - return TRUE; - } - // hidden edit menu for cut/copy/paste - if (gEditMenu && gEditMenu->handleAcceleratorKey(key, mask)) - { - return TRUE; - } - - // Traverses up the hierarchy - if( keyboard_focus ) - { - LLLineEditor* chat_editor = LLBottomTray::instanceExists() ? LLBottomTray::getInstance()->getNearbyChatBar()->getChatBox() : NULL; - // arrow keys move avatar while chatting hack - if (chat_editor && chat_editor->hasFocus()) - { - // If text field is empty, there's no point in trying to move - // cursor with arrow keys, so allow movement - if (chat_editor->getText().empty() - || gSavedSettings.getBOOL("ArrowKeysAlwaysMove")) - { - // let Control-Up and Control-Down through for chat line history, - if (!(key == KEY_UP && mask == MASK_CONTROL) - && !(key == KEY_DOWN && mask == MASK_CONTROL)) - { - switch(key) - { - case KEY_LEFT: - case KEY_RIGHT: - case KEY_UP: - case KEY_DOWN: - case KEY_PAGE_UP: - case KEY_PAGE_DOWN: - case KEY_HOME: - // when chatbar is empty or ArrowKeysAlwaysMove set, - // pass arrow keys on to avatar... - return FALSE; - default: - break; - } - } - } - } - - if (keyboard_focus->handleKey(key, mask, FALSE)) - { - return TRUE; - } - } - - if( LLToolMgr::getInstance()->getCurrentTool()->handleKey(key, mask) ) - { - return TRUE; - } - - // Try for a new-format gesture - if (LLGestureMgr::instance().triggerGesture(key, mask)) - { - return TRUE; - } - - // See if this is a gesture trigger. If so, eat the key and - // don't pass it down to the menus. - if (gGestureList.trigger(key, mask)) - { - return TRUE; - } - - // If "Pressing letter keys starts local chat" option is selected, we are not in mouselook, - // no view has keyboard focus, this is a printable character key (and no modifier key is - // pressed except shift), then give focus to nearby chat (STORM-560) - if ( gSavedSettings.getS32("LetterKeysFocusChatBar") && !gAgentCamera.cameraMouselook() && - !keyboard_focus && key < 0x80 && (mask == MASK_NONE || mask == MASK_SHIFT) ) - { - LLLineEditor* chat_editor = LLBottomTray::instanceExists() ? LLBottomTray::getInstance()->getNearbyChatBar()->getChatBox() : NULL; - if (chat_editor) - { - // passing NULL here, character will be added later when it is handled by character handler. - LLBottomTray::getInstance()->getNearbyChatBar()->startChat(NULL); - return TRUE; - } - } - - // give menus a chance to handle unmodified accelerator keys - if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask)) - ||(gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask))) - { - return TRUE; - } - - // don't pass keys on to world when something in ui has focus - return gFocusMgr.childHasKeyboardFocus(mRootView) - || LLMenuGL::getKeyboardMode() - || (gMenuBarView && gMenuBarView->getHighlightedItem() && gMenuBarView->getHighlightedItem()->isActive()); -} - - -BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask) -{ - // HACK: We delay processing of return keys until they arrive as a Unicode char, - // so that if you're typing chat text at low frame rate, we don't send the chat - // until all keystrokes have been entered. JC - // HACK: Numeric keypad <enter> on Mac is Unicode 3 - // HACK: Control-M on Windows is Unicode 13 - if ((uni_char == 13 && mask != MASK_CONTROL) - || (uni_char == 3 && mask == MASK_NONE)) - { - return gViewerKeyboard.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN)); - } - - // let menus handle navigation (jump) keys - if (gMenuBarView && gMenuBarView->handleUnicodeChar(uni_char, TRUE)) - { - return TRUE; - } - - // Traverses up the hierarchy - LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus(); - if( keyboard_focus ) - { - if (keyboard_focus->handleUnicodeChar(uni_char, FALSE)) - { - return TRUE; - } - - //// Topmost view gets a chance before the hierarchy - //LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); - //if (top_ctrl && top_ctrl->handleUnicodeChar( uni_char, FALSE ) ) - //{ - // return TRUE; - //} - - return TRUE; - } - - return FALSE; -} - - -void LLViewerWindow::handleScrollWheel(S32 clicks) -{ - LLView::sMouseHandlerMessage.clear(); - - LLUI::resetMouseIdleTimer(); - - LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture(); - if( mouse_captor ) - { - S32 local_x; - S32 local_y; - mouse_captor->screenPointToLocal( mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y ); - mouse_captor->handleScrollWheel(local_x, local_y, clicks); - if (LLView::sDebugMouseHandling) - { - llinfos << "Scroll Wheel handled by captor " << mouse_captor->getName() << llendl; - } - return; - } - - LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); - if (top_ctrl) - { - S32 local_x; - S32 local_y; - top_ctrl->screenPointToLocal( mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y ); - if (top_ctrl->handleScrollWheel(local_x, local_y, clicks)) return; - } - - if (mRootView->handleScrollWheel(mCurrentMousePoint.mX, mCurrentMousePoint.mY, clicks) ) - { - if (LLView::sDebugMouseHandling) - { - llinfos << "Scroll Wheel" << LLView::sMouseHandlerMessage << llendl; - } - return; - } - else if (LLView::sDebugMouseHandling) - { - llinfos << "Scroll Wheel not handled by view" << llendl; - } - - // Zoom the camera in and out behavior - - if(top_ctrl == 0 - && getWorldViewRectScaled().pointInRect(mCurrentMousePoint.mX, mCurrentMousePoint.mY) - && gAgentCamera.isInitialized()) - gAgentCamera.handleScrollWheel(clicks); - - return; -} - -void LLViewerWindow::addPopup(LLView* popup) -{ - if (mPopupView) - { - mPopupView->addPopup(popup); - } -} - -void LLViewerWindow::removePopup(LLView* popup) -{ - if (mPopupView) - { - mPopupView->removePopup(popup); - } -} - -void LLViewerWindow::clearPopups() -{ - if (mPopupView) - { - mPopupView->clearPopups(); - } -} - -void LLViewerWindow::moveCursorToCenter() -{ - if (! gSavedSettings.getBOOL("DisableMouseWarp")) - { - S32 x = getWorldViewWidthScaled() / 2; - S32 y = getWorldViewHeightScaled() / 2; - - //on a forced move, all deltas get zeroed out to prevent jumping - mCurrentMousePoint.set(x,y); - mLastMousePoint.set(x,y); - mCurrentMouseDelta.set(0,0); - - LLUI::setMousePositionScreen(x, y); - } -} - - -////////////////////////////////////////////////////////////////////// -// -// Hover handlers -// - -void append_xui_tooltip(LLView* viewp, LLToolTip::Params& params) -{ - if (viewp) - { - if (!params.styled_message.empty()) - { - params.styled_message.add().text("\n---------\n"); - } - LLView::root_to_view_iterator_t end_tooltip_it = viewp->endRootToView(); - // NOTE: we skip "root" since it is assumed - for (LLView::root_to_view_iterator_t tooltip_it = ++viewp->beginRootToView(); - tooltip_it != end_tooltip_it; - ++tooltip_it) - { - LLView* viewp = *tooltip_it; - - params.styled_message.add().text(viewp->getName()); - - LLPanel* panelp = dynamic_cast<LLPanel*>(viewp); - if (panelp && !panelp->getXMLFilename().empty()) - { - params.styled_message.add() - .text("(" + panelp->getXMLFilename() + ")") - .style.color(LLColor4(0.7f, 0.7f, 1.f, 1.f)); - } - params.styled_message.add().text("/"); - } - } -} - -// Update UI based on stored mouse position from mouse-move -// event processing. -void LLViewerWindow::updateUI() -{ - static LLFastTimer::DeclareTimer ftm("Update UI"); - LLFastTimer t(ftm); - - static std::string last_handle_msg; - - if (gLoggedInTime.getStarted()) - { - if (gLoggedInTime.getElapsedTimeF32() > gSavedSettings.getF32("DestinationGuideHintTimeout")) - { - LLFirstUse::notUsingDestinationGuide(); - } - if (gLoggedInTime.getElapsedTimeF32() > gSavedSettings.getF32("SidePanelHintTimeout")) - { - LLFirstUse::notUsingSidePanel(); - } - } - - LLConsole::updateClass(); - - // animate layout stacks so we have up to date rect for world view - LLLayoutStack::updateClass(); - - // use full window for world view when not rendering UI - bool world_view_uses_full_window = gAgentCamera.cameraMouselook() || !gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI); - updateWorldViewRect(world_view_uses_full_window); - - LLView::sMouseHandlerMessage.clear(); - - S32 x = mCurrentMousePoint.mX; - S32 y = mCurrentMousePoint.mY; - MASK mask = gKeyboard->currentMask(TRUE); - - if (gNoRender) - { - return; - } - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST)) - { - gDebugRaycastFaceHit = -1; - gDebugRaycastObject = cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, - &gDebugRaycastFaceHit, - &gDebugRaycastIntersection, - &gDebugRaycastTexCoord, - &gDebugRaycastNormal, - &gDebugRaycastBinormal); - } - - updateMouseDelta(); - updateKeyboardFocus(); - - BOOL handled = FALSE; - - BOOL handled_by_top_ctrl = FALSE; - LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); - LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture(); - LLView* captor_view = dynamic_cast<LLView*>(mouse_captor); - - //FIXME: only include captor and captor's ancestors if mouse is truly over them --RN - - //build set of views containing mouse cursor by traversing UI hierarchy and testing - //screen rect against mouse cursor - view_handle_set_t mouse_hover_set; - - // constraint mouse enter events to children of mouse captor - LLView* root_view = captor_view; - - // if mouse captor doesn't exist or isn't a LLView - // then allow mouse enter events on entire UI hierarchy - if (!root_view) - { - root_view = mRootView; - } - - // only update mouse hover set when UI is visible (since we shouldn't send hover events to invisible UI - if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) - { - // include all ancestors of captor_view as automatically having mouse - if (captor_view) - { - LLView* captor_parent_view = captor_view->getParent(); - while(captor_parent_view) - { - mouse_hover_set.insert(captor_parent_view->getHandle()); - captor_parent_view = captor_parent_view->getParent(); - } - } - - // aggregate visible views that contain mouse cursor in display order - LLPopupView::popup_list_t popups = mPopupView->getCurrentPopups(); - - for(LLPopupView::popup_list_t::iterator popup_it = popups.begin(); popup_it != popups.end(); ++popup_it) - { - LLView* popup = popup_it->get(); - if (popup && popup->calcScreenBoundingRect().pointInRect(x, y)) - { - // iterator over contents of top_ctrl, and throw into mouse_hover_set - for (LLView::tree_iterator_t it = popup->beginTreeDFS(); - it != popup->endTreeDFS(); - ++it) - { - LLView* viewp = *it; - if (viewp->getVisible() - && viewp->calcScreenBoundingRect().pointInRect(x, y)) - { - // we have a view that contains the mouse, add it to the set - mouse_hover_set.insert(viewp->getHandle()); - } - else - { - // skip this view and all of its children - it.skipDescendants(); - } - } - } - } - - // while the top_ctrl contains the mouse cursor, only it and its descendants will receive onMouseEnter events - if (top_ctrl && top_ctrl->calcScreenBoundingRect().pointInRect(x, y)) - { - // iterator over contents of top_ctrl, and throw into mouse_hover_set - for (LLView::tree_iterator_t it = top_ctrl->beginTreeDFS(); - it != top_ctrl->endTreeDFS(); - ++it) - { - LLView* viewp = *it; - if (viewp->getVisible() - && viewp->calcScreenBoundingRect().pointInRect(x, y)) - { - // we have a view that contains the mouse, add it to the set - mouse_hover_set.insert(viewp->getHandle()); - } - else - { - // skip this view and all of its children - it.skipDescendants(); - } - } - } - else - { - // walk UI tree in depth-first order - for (LLView::tree_iterator_t it = root_view->beginTreeDFS(); - it != root_view->endTreeDFS(); - ++it) - { - LLView* viewp = *it; - // calculating the screen rect involves traversing the parent, so this is less than optimal - if (viewp->getVisible() - && viewp->calcScreenBoundingRect().pointInRect(x, y)) - { - - // if this view is mouse opaque, nothing behind it should be in mouse_hover_set - if (viewp->getMouseOpaque()) - { - // constrain further iteration to children of this widget - it = viewp->beginTreeDFS(); - } - - // we have a view that contains the mouse, add it to the set - mouse_hover_set.insert(viewp->getHandle()); - } - else - { - // skip this view and all of its children - it.skipDescendants(); - } - } - } - } - - typedef std::vector<LLHandle<LLView> > view_handle_list_t; - - // call onMouseEnter() on all views which contain the mouse cursor but did not before - view_handle_list_t mouse_enter_views; - std::set_difference(mouse_hover_set.begin(), mouse_hover_set.end(), - mMouseHoverViews.begin(), mMouseHoverViews.end(), - std::back_inserter(mouse_enter_views)); - for (view_handle_list_t::iterator it = mouse_enter_views.begin(); - it != mouse_enter_views.end(); - ++it) - { - LLView* viewp = it->get(); - if (viewp) - { - LLRect view_screen_rect = viewp->calcScreenRect(); - viewp->onMouseEnter(x - view_screen_rect.mLeft, y - view_screen_rect.mBottom, mask); - } - } - - // call onMouseLeave() on all views which no longer contain the mouse cursor - view_handle_list_t mouse_leave_views; - std::set_difference(mMouseHoverViews.begin(), mMouseHoverViews.end(), - mouse_hover_set.begin(), mouse_hover_set.end(), - std::back_inserter(mouse_leave_views)); - for (view_handle_list_t::iterator it = mouse_leave_views.begin(); - it != mouse_leave_views.end(); - ++it) - { - LLView* viewp = it->get(); - if (viewp) - { - LLRect view_screen_rect = viewp->calcScreenRect(); - viewp->onMouseLeave(x - view_screen_rect.mLeft, y - view_screen_rect.mBottom, mask); - } - } - - // store resulting hover set for next frame - swap(mMouseHoverViews, mouse_hover_set); - - // only handle hover events when UI is enabled - if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) - { - - if( mouse_captor ) - { - // Pass hover events to object capturing mouse events. - S32 local_x; - S32 local_y; - mouse_captor->screenPointToLocal( x, y, &local_x, &local_y ); - handled = mouse_captor->handleHover(local_x, local_y, mask); - if (LLView::sDebugMouseHandling) - { - llinfos << "Hover handled by captor " << mouse_captor->getName() << llendl; - } - - if( !handled ) - { - lldebugst(LLERR_USER_INPUT) << "hover not handled by mouse captor" << llendl; - } - } - else - { - if (top_ctrl) - { - S32 local_x, local_y; - top_ctrl->screenPointToLocal( x, y, &local_x, &local_y ); - handled = top_ctrl->pointInView(local_x, local_y) && top_ctrl->handleHover(local_x, local_y, mask); - handled_by_top_ctrl = TRUE; - } - - if ( !handled ) - { - // x and y are from last time mouse was in window - // mMouseInWindow tracks *actual* mouse location - if (mMouseInWindow && mRootView->handleHover(x, y, mask) ) - { - if (LLView::sDebugMouseHandling && LLView::sMouseHandlerMessage != last_handle_msg) - { - last_handle_msg = LLView::sMouseHandlerMessage; - llinfos << "Hover" << LLView::sMouseHandlerMessage << llendl; - } - handled = TRUE; - } - else if (LLView::sDebugMouseHandling) - { - if (last_handle_msg != LLStringUtil::null) - { - last_handle_msg.clear(); - llinfos << "Hover not handled by view" << llendl; - } - } - } - - if (!handled) - { - LLTool *tool = LLToolMgr::getInstance()->getCurrentTool(); - - if(mMouseInWindow && tool) - { - handled = tool->handleHover(x, y, mask); - } - } - } - - // Show a new tool tip (or update one that is already shown) - BOOL tool_tip_handled = FALSE; - std::string tool_tip_msg; - if( handled - && !mWindow->isCursorHidden()) - { - LLRect screen_sticky_rect = mRootView->getLocalRect(); - S32 local_x, local_y; - - if (gSavedSettings.getBOOL("DebugShowXUINames")) - { - LLToolTip::Params params; - - LLView* tooltip_view = mRootView; - LLView::tree_iterator_t end_it = mRootView->endTreeDFS(); - for (LLView::tree_iterator_t it = mRootView->beginTreeDFS(); it != end_it; ++it) - { - LLView* viewp = *it; - LLRect screen_rect; - viewp->localRectToScreen(viewp->getLocalRect(), &screen_rect); - if (!(viewp->getVisible() - && screen_rect.pointInRect(x, y))) - { - it.skipDescendants(); - } - // only report xui names for LLUICtrls, - // and blacklist the various containers we don't care about - else if (dynamic_cast<LLUICtrl*>(viewp) - && viewp != gMenuHolder - && viewp != gFloaterView - && viewp != gConsole) - { - if (dynamic_cast<LLFloater*>(viewp)) - { - // constrain search to descendants of this (frontmost) floater - // by resetting iterator - it = viewp->beginTreeDFS(); - } - - // if we are in a new part of the tree (not a descendent of current tooltip_view) - // then push the results for tooltip_view and start with a new potential view - // NOTE: this emulates visiting only the leaf nodes that meet our criteria - if (!viewp->hasAncestor(tooltip_view)) - { - append_xui_tooltip(tooltip_view, params); - screen_sticky_rect.intersectWith(tooltip_view->calcScreenRect()); - } - tooltip_view = viewp; - } - } - - append_xui_tooltip(tooltip_view, params); - screen_sticky_rect.intersectWith(tooltip_view->calcScreenRect()); - - params.sticky_rect = screen_sticky_rect; - params.max_width = 400; - - LLToolTipMgr::instance().show(params); - } - // if there is a mouse captor, nothing else gets a tooltip - else if (mouse_captor) - { - mouse_captor->screenPointToLocal(x, y, &local_x, &local_y); - tool_tip_handled = mouse_captor->handleToolTip(local_x, local_y, mask); - } - else - { - // next is top_ctrl - if (!tool_tip_handled && top_ctrl) - { - top_ctrl->screenPointToLocal(x, y, &local_x, &local_y); - tool_tip_handled = top_ctrl->handleToolTip(local_x, local_y, mask ); - } - - if (!tool_tip_handled) - { - local_x = x; local_y = y; - tool_tip_handled = mRootView->handleToolTip(local_x, local_y, mask ); - } - - LLTool* current_tool = LLToolMgr::getInstance()->getCurrentTool(); - if (!tool_tip_handled && current_tool) - { - current_tool->screenPointToLocal(x, y, &local_x, &local_y); - tool_tip_handled = current_tool->handleToolTip(local_x, local_y, mask ); - } - } - } - } - else - { // just have tools handle hover when UI is turned off - LLTool *tool = LLToolMgr::getInstance()->getCurrentTool(); - - if(mMouseInWindow && tool) - { - handled = tool->handleHover(x, y, mask); - } - } - - updateLayout(); - - mLastMousePoint = mCurrentMousePoint; - - // cleanup unused selections when no modal dialogs are open - if (LLModalDialog::activeCount() == 0) - { - LLViewerParcelMgr::getInstance()->deselectUnused(); - } - - if (LLModalDialog::activeCount() == 0) - { - LLSelectMgr::getInstance()->deselectUnused(); - } -} - - -void LLViewerWindow::updateLayout() -{ - LLTool* tool = LLToolMgr::getInstance()->getCurrentTool(); - if (gFloaterTools != NULL - && tool != NULL - && tool != gToolNull - && tool != LLToolCompInspect::getInstance() - && tool != LLToolDragAndDrop::getInstance() - && !gSavedSettings.getBOOL("FreezeTime")) - { - // Suppress the toolbox view if our source tool was the pie tool, - // and we've overridden to something else. - bool suppress_toolbox = - (LLToolMgr::getInstance()->getBaseTool() == LLToolPie::getInstance()) && - (LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance()); - - LLMouseHandler *captor = gFocusMgr.getMouseCapture(); - // With the null, inspect, or drag and drop tool, don't muck - // with visibility. - - if (gFloaterTools->isMinimized() - || (tool != LLToolPie::getInstance() // not default tool - && tool != LLToolCompGun::getInstance() // not coming out of mouselook - && !suppress_toolbox // not override in third person - && LLToolMgr::getInstance()->getCurrentToolset() != gFaceEditToolset // not special mode - && LLToolMgr::getInstance()->getCurrentToolset() != gMouselookToolset - && (!captor || dynamic_cast<LLView*>(captor) != NULL))) // not dragging - { - // Force floater tools to be visible (unless minimized) - if (!gFloaterTools->getVisible()) - { - gFloaterTools->openFloater(); - } - // Update the location of the blue box tool popup - LLCoordGL select_center_screen; - gFloaterTools->updatePopup( select_center_screen, gKeyboard->currentMask(TRUE) ); - } - else - { - gFloaterTools->setVisible(FALSE); - } - //gMenuBarView->setItemVisible("BuildTools", gFloaterTools->getVisible()); - } - - // Always update console - if(gConsole) - { - LLRect console_rect = getChatConsoleRect(); - gConsole->reshape(console_rect.getWidth(), console_rect.getHeight()); - gConsole->setRect(console_rect); - } -} - -void LLViewerWindow::updateMouseDelta() -{ - S32 dx = lltrunc((F32) (mCurrentMousePoint.mX - mLastMousePoint.mX) * LLUI::sGLScaleFactor.mV[VX]); - S32 dy = lltrunc((F32) (mCurrentMousePoint.mY - mLastMousePoint.mY) * LLUI::sGLScaleFactor.mV[VY]); - - //RN: fix for asynchronous notification of mouse leaving window not working - LLCoordWindow mouse_pos; - mWindow->getCursorPosition(&mouse_pos); - if (mouse_pos.mX < 0 || - mouse_pos.mY < 0 || - mouse_pos.mX > mWindowRectRaw.getWidth() || - mouse_pos.mY > mWindowRectRaw.getHeight()) - { - mMouseInWindow = FALSE; - } - else - { - mMouseInWindow = TRUE; - } - - LLVector2 mouse_vel; - - if (gSavedSettings.getBOOL("MouseSmooth")) - { - static F32 fdx = 0.f; - static F32 fdy = 0.f; - - F32 amount = 16.f; - fdx = fdx + ((F32) dx - fdx) * llmin(gFrameIntervalSeconds*amount,1.f); - fdy = fdy + ((F32) dy - fdy) * llmin(gFrameIntervalSeconds*amount,1.f); - - mCurrentMouseDelta.set(llround(fdx), llround(fdy)); - mouse_vel.setVec(fdx,fdy); - } - else - { - mCurrentMouseDelta.set(dx, dy); - mouse_vel.setVec((F32) dx, (F32) dy); - } - - mMouseVelocityStat.addValue(mouse_vel.magVec()); -} - -void LLViewerWindow::updateKeyboardFocus() -{ - if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) - { - gFocusMgr.setKeyboardFocus(NULL); - } - - // clean up current focus - LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus()); - if (cur_focus) - { - if (!cur_focus->isInVisibleChain() || !cur_focus->isInEnabledChain()) - { - // don't release focus, just reassign so that if being given - // to a sibling won't call onFocusLost on all the ancestors - // gFocusMgr.releaseFocusIfNeeded(cur_focus); - - LLUICtrl* parent = cur_focus->getParentUICtrl(); - const LLUICtrl* focus_root = cur_focus->findRootMostFocusRoot(); - bool new_focus_found = false; - while(parent) - { - if (parent->isCtrl() - && (parent->hasTabStop() || parent == focus_root) - && !parent->getIsChrome() - && parent->isInVisibleChain() - && parent->isInEnabledChain()) - { - if (!parent->focusFirstItem()) - { - parent->setFocus(TRUE); - } - new_focus_found = true; - break; - } - parent = parent->getParentUICtrl(); - } - - // if we didn't find a better place to put focus, just release it - // hasFocus() will return true if and only if we didn't touch focus since we - // are only moving focus higher in the hierarchy - if (!new_focus_found) - { - cur_focus->setFocus(FALSE); - } - } - else if (cur_focus->isFocusRoot()) - { - // focus roots keep trying to delegate focus to their first valid descendant - // this assumes that focus roots are not valid focus holders on their own - cur_focus->focusFirstItem(); - } - } - - // last ditch force of edit menu to selection manager - if (LLEditMenuHandler::gEditMenuHandler == NULL && LLSelectMgr::getInstance()->getSelection()->getObjectCount()) - { - LLEditMenuHandler::gEditMenuHandler = LLSelectMgr::getInstance(); - } - - if (gFloaterView->getCycleMode()) - { - // sync all floaters with their focus state - gFloaterView->highlightFocusedFloater(); - gSnapshotFloaterView->highlightFocusedFloater(); - if ((gKeyboard->currentMask(TRUE) & MASK_CONTROL) == 0) - { - // control key no longer held down, finish cycle mode - gFloaterView->setCycleMode(FALSE); - - gFloaterView->syncFloaterTabOrder(); - } - else - { - // user holding down CTRL, don't update tab order of floaters - } - } - else - { - // update focused floater - gFloaterView->highlightFocusedFloater(); - gSnapshotFloaterView->highlightFocusedFloater(); - // make sure floater visible order is in sync with tab order - gFloaterView->syncFloaterTabOrder(); - } - - if(LLSideTray::instanceCreated())//just getInstance will create sidetray. we don't want this - LLSideTray::getInstance()->highlightFocused(); -} - -static LLFastTimer::DeclareTimer FTM_UPDATE_WORLD_VIEW("Update World View"); -void LLViewerWindow::updateWorldViewRect(bool use_full_window) -{ - LLFastTimer ft(FTM_UPDATE_WORLD_VIEW); - - // start off using whole window to render world - LLRect new_world_rect = mWindowRectRaw; - - if (use_full_window == false && mWorldViewPlaceholder.get()) - { - new_world_rect = mWorldViewPlaceholder.get()->calcScreenRect(); - // clamp to at least a 1x1 rect so we don't try to allocate zero width gl buffers - new_world_rect.mTop = llmax(new_world_rect.mTop, new_world_rect.mBottom + 1); - new_world_rect.mRight = llmax(new_world_rect.mRight, new_world_rect.mLeft + 1); - - new_world_rect.mLeft = llround((F32)new_world_rect.mLeft * mDisplayScale.mV[VX]); - new_world_rect.mRight = llround((F32)new_world_rect.mRight * mDisplayScale.mV[VX]); - new_world_rect.mBottom = llround((F32)new_world_rect.mBottom * mDisplayScale.mV[VY]); - new_world_rect.mTop = llround((F32)new_world_rect.mTop * mDisplayScale.mV[VY]); - } - - if (gSavedSettings.getBOOL("SidebarCameraMovement") == FALSE) - { - // use right edge of window, ignoring sidebar - new_world_rect.mRight = mWindowRectRaw.mRight; - } - - if (mWorldViewRectRaw != new_world_rect) - { - mWorldViewRectRaw = new_world_rect; - gResizeScreenTexture = TRUE; - LLViewerCamera::getInstance()->setViewHeightInPixels( mWorldViewRectRaw.getHeight() ); - LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() ); - - LLRect old_world_rect_scaled = mWorldViewRectScaled; - mWorldViewRectScaled = calcScaledRect(mWorldViewRectRaw, mDisplayScale); - - // sending a signal with a new WorldView rect - mOnWorldViewRectUpdated(old_world_rect_scaled, mWorldViewRectScaled); - } -} - -void LLViewerWindow::saveLastMouse(const LLCoordGL &point) -{ - // Store last mouse location. - // If mouse leaves window, pretend last point was on edge of window - if (point.mX < 0) - { - mCurrentMousePoint.mX = 0; - } - else if (point.mX > getWindowWidthScaled()) - { - mCurrentMousePoint.mX = getWindowWidthScaled(); - } - else - { - mCurrentMousePoint.mX = point.mX; - } - - if (point.mY < 0) - { - mCurrentMousePoint.mY = 0; - } - else if (point.mY > getWindowHeightScaled() ) - { - mCurrentMousePoint.mY = getWindowHeightScaled(); - } - else - { - mCurrentMousePoint.mY = point.mY; - } -} - - -// Draws the selection outlines for the currently selected objects -// Must be called after displayObjects is called, which sets the mGLName parameter -// NOTE: This function gets called 3 times: -// render_ui_3d: FALSE, FALSE, TRUE -// render_hud_elements: FALSE, FALSE, FALSE -void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls, BOOL for_hud ) -{ - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - - if (!for_hud && !for_gl_pick) - { - // Call this once and only once - LLSelectMgr::getInstance()->updateSilhouettes(); - } - - // Draw fence around land selections - if (for_gl_pick) - { - if (pick_parcel_walls) - { - LLViewerParcelMgr::getInstance()->renderParcelCollision(); - } - } - else if (( for_hud && selection->getSelectType() == SELECT_TYPE_HUD) || - (!for_hud && selection->getSelectType() != SELECT_TYPE_HUD)) - { - LLSelectMgr::getInstance()->renderSilhouettes(for_hud); - - stop_glerror(); - - // setup HUD render - if (selection->getSelectType() == SELECT_TYPE_HUD && LLSelectMgr::getInstance()->getSelection()->getObjectCount()) - { - LLBBox hud_bbox = gAgentAvatarp->getHUDBBox(); - - // set up transform to encompass bounding box of HUD - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - F32 depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f); - glOrtho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, depth); - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glLoadMatrixf(OGL_TO_CFR_ROTATION); // Load Cory's favorite reference frame - glTranslatef(-hud_bbox.getCenterLocal().mV[VX] + (depth *0.5f), 0.f, 0.f); - } - - // Render light for editing - if (LLSelectMgr::sRenderLightRadius && LLToolMgr::getInstance()->inEdit()) - { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLGLEnable gls_blend(GL_BLEND); - LLGLEnable gls_cull(GL_CULL_FACE); - LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - if (selection->getSelectType() == SELECT_TYPE_HUD) - { - F32 zoom = gAgentCamera.mHUDCurZoom; - glScalef(zoom, zoom, zoom); - } - - struct f : public LLSelectedObjectFunctor - { - virtual bool apply(LLViewerObject* object) - { - LLDrawable* drawable = object->mDrawable; - if (drawable && drawable->isLight()) - { - LLVOVolume* vovolume = drawable->getVOVolume(); - glPushMatrix(); - - LLVector3 center = drawable->getPositionAgent(); - glTranslatef(center[0], center[1], center[2]); - F32 scale = vovolume->getLightRadius(); - glScalef(scale, scale, scale); - - LLColor4 color(vovolume->getLightColor(), .5f); - glColor4fv(color.mV); - - F32 pixel_area = 100000.f; - // Render Outside - gSphere.render(pixel_area); - - // Render Inside - glCullFace(GL_FRONT); - gSphere.render(pixel_area); - glCullFace(GL_BACK); - - glPopMatrix(); - } - return true; - } - } func; - LLSelectMgr::getInstance()->getSelection()->applyToObjects(&func); - - glPopMatrix(); - } - - // NOTE: The average position for the axis arrows of the selected objects should - // not be recalculated at this time. If they are, then group rotations will break. - - // Draw arrows at average center of all selected objects - LLTool* tool = LLToolMgr::getInstance()->getCurrentTool(); - if (tool) - { - if(tool->isAlwaysRendered()) - { - tool->render(); - } - else - { - if( !LLSelectMgr::getInstance()->getSelection()->isEmpty() ) - { - BOOL moveable_object_selected = FALSE; - BOOL all_selected_objects_move = TRUE; - BOOL all_selected_objects_modify = TRUE; - BOOL selecting_linked_set = !gSavedSettings.getBOOL("EditLinkedParts"); - - for (LLObjectSelection::iterator iter = LLSelectMgr::getInstance()->getSelection()->begin(); - iter != LLSelectMgr::getInstance()->getSelection()->end(); iter++) - { - LLSelectNode* nodep = *iter; - LLViewerObject* object = nodep->getObject(); - BOOL this_object_movable = FALSE; - if (object->permMove() && (object->permModify() || selecting_linked_set)) - { - moveable_object_selected = TRUE; - this_object_movable = TRUE; - } - all_selected_objects_move = all_selected_objects_move && this_object_movable; - all_selected_objects_modify = all_selected_objects_modify && object->permModify(); - } - - BOOL draw_handles = TRUE; - - if (tool == LLToolCompTranslate::getInstance() && (!moveable_object_selected || !all_selected_objects_move)) - { - draw_handles = FALSE; - } - - if (tool == LLToolCompRotate::getInstance() && (!moveable_object_selected || !all_selected_objects_move)) - { - draw_handles = FALSE; - } - - if ( !all_selected_objects_modify && tool == LLToolCompScale::getInstance() ) - { - draw_handles = FALSE; - } - - if( draw_handles ) - { - tool->render(); - } - } - } - if (selection->getSelectType() == SELECT_TYPE_HUD && selection->getObjectCount()) - { - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - stop_glerror(); - } - } - } -} - -// Return a point near the clicked object representative of the place the object was clicked. -LLVector3d LLViewerWindow::clickPointInWorldGlobal(S32 x, S32 y_from_bot, LLViewerObject* clicked_object) const -{ - // create a normalized vector pointing from the camera center into the - // world at the location of the mouse click - LLVector3 mouse_direction_global = mouseDirectionGlobal( x, y_from_bot ); - - LLVector3d relative_object = clicked_object->getPositionGlobal() - gAgentCamera.getCameraPositionGlobal(); - - // make mouse vector as long as object vector, so it touchs a point near - // where the user clicked on the object - mouse_direction_global *= (F32) relative_object.magVec(); - - LLVector3d new_pos; - new_pos.setVec(mouse_direction_global); - // transform mouse vector back to world coords - new_pos += gAgentCamera.getCameraPositionGlobal(); - - return new_pos; -} - - -BOOL LLViewerWindow::clickPointOnSurfaceGlobal(const S32 x, const S32 y, LLViewerObject *objectp, LLVector3d &point_global) const -{ - BOOL intersect = FALSE; - -// U8 shape = objectp->mPrimitiveCode & LL_PCODE_BASE_MASK; - if (!intersect) - { - point_global = clickPointInWorldGlobal(x, y, objectp); - llinfos << "approx intersection at " << (objectp->getPositionGlobal() - point_global) << llendl; - } - else - { - llinfos << "good intersection at " << (objectp->getPositionGlobal() - point_global) << llendl; - } - - return intersect; -} - -void LLViewerWindow::pickAsync(S32 x, S32 y_from_bot, MASK mask, void (*callback)(const LLPickInfo& info), BOOL pick_transparent) -{ - if (gNoRender) - { - return; - } - - BOOL in_build_mode = LLFloaterReg::instanceVisible("build"); - if (in_build_mode || LLDrawPoolAlpha::sShowDebugAlpha) - { - // build mode allows interaction with all transparent objects - // "Show Debug Alpha" means no object actually transparent - pick_transparent = TRUE; - } - - LLPickInfo pick_info(LLCoordGL(x, y_from_bot), mask, pick_transparent, TRUE, callback); - schedulePick(pick_info); -} - -void LLViewerWindow::schedulePick(LLPickInfo& pick_info) -{ - if (mPicks.size() >= 1024 || mWindow->getMinimized()) - { //something went wrong, picks are being scheduled but not processed - - if (pick_info.mPickCallback) - { - pick_info.mPickCallback(pick_info); - } - - return; - } - mPicks.push_back(pick_info); - - // delay further event processing until we receive results of pick - // only do this for async picks so that handleMouseUp won't be called - // until the pick triggered in handleMouseDown has been processed, for example - mWindow->delayInputProcessing(); -} - - -void LLViewerWindow::performPick() -{ - if (gNoRender) - { - return; - } - - if (!mPicks.empty()) - { - std::vector<LLPickInfo>::iterator pick_it; - for (pick_it = mPicks.begin(); pick_it != mPicks.end(); ++pick_it) - { - pick_it->fetchResults(); - } - - mLastPick = mPicks.back(); - mPicks.clear(); - } -} - -void LLViewerWindow::returnEmptyPicks() -{ - std::vector<LLPickInfo>::iterator pick_it; - for (pick_it = mPicks.begin(); pick_it != mPicks.end(); ++pick_it) - { - mLastPick = *pick_it; - // just trigger callback with empty results - if (pick_it->mPickCallback) - { - pick_it->mPickCallback(*pick_it); - } - } - mPicks.clear(); -} - -// Performs the GL object/land pick. -LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, BOOL pick_transparent) -{ - if (gNoRender) - { - return LLPickInfo(); - } - - BOOL in_build_mode = LLFloaterReg::instanceVisible("build"); - if (in_build_mode || LLDrawPoolAlpha::sShowDebugAlpha) - { - // build mode allows interaction with all transparent objects - // "Show Debug Alpha" means no object actually transparent - pick_transparent = TRUE; - } - - // shortcut queueing in mPicks and just update mLastPick in place - mLastPick = LLPickInfo(LLCoordGL(x, y_from_bot), gKeyboard->currentMask(TRUE), pick_transparent, TRUE, NULL); - mLastPick.fetchResults(); - - return mLastPick; -} - -LLHUDIcon* LLViewerWindow::cursorIntersectIcon(S32 mouse_x, S32 mouse_y, F32 depth, - LLVector3* intersection) -{ - S32 x = mouse_x; - S32 y = mouse_y; - - if ((mouse_x == -1) && (mouse_y == -1)) // use current mouse position - { - x = getCurrentMouseX(); - y = getCurrentMouseY(); - } - - // world coordinates of mouse - LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y); - LLVector3 mouse_point_global = LLViewerCamera::getInstance()->getOrigin(); - LLVector3 mouse_world_start = mouse_point_global; - LLVector3 mouse_world_end = mouse_point_global + mouse_direction_global * depth; - - return LLHUDIcon::lineSegmentIntersectAll(mouse_world_start, mouse_world_end, intersection); - - -} - -LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 depth, - LLViewerObject *this_object, - S32 this_face, - BOOL pick_transparent, - S32* face_hit, - LLVector3 *intersection, - LLVector2 *uv, - LLVector3 *normal, - LLVector3 *binormal) -{ - S32 x = mouse_x; - S32 y = mouse_y; - - if ((mouse_x == -1) && (mouse_y == -1)) // use current mouse position - { - x = getCurrentMouseX(); - y = getCurrentMouseY(); - } - - // HUD coordinates of mouse - LLVector3 mouse_point_hud = mousePointHUD(x, y); - LLVector3 mouse_hud_start = mouse_point_hud - LLVector3(depth, 0, 0); - LLVector3 mouse_hud_end = mouse_point_hud + LLVector3(depth, 0, 0); - - // world coordinates of mouse - LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y); - LLVector3 mouse_point_global = LLViewerCamera::getInstance()->getOrigin(); - - //get near clip plane - LLVector3 n = LLViewerCamera::getInstance()->getAtAxis(); - LLVector3 p = mouse_point_global + n * LLViewerCamera::getInstance()->getNear(); - - //project mouse point onto plane - LLVector3 pos; - line_plane(mouse_point_global, mouse_direction_global, p, n, pos); - mouse_point_global = pos; - - LLVector3 mouse_world_start = mouse_point_global; - LLVector3 mouse_world_end = mouse_point_global + mouse_direction_global * depth; - - - LLViewerObject* found = NULL; - - if (this_object) // check only this object - { - if (this_object->isHUDAttachment()) // is a HUD object? - { - if (this_object->lineSegmentIntersect(mouse_hud_start, mouse_hud_end, this_face, pick_transparent, - face_hit, intersection, uv, normal, binormal)) - { - found = this_object; - } - } - - else // is a world object - { - if (this_object->lineSegmentIntersect(mouse_world_start, mouse_world_end, this_face, pick_transparent, - face_hit, intersection, uv, normal, binormal)) - { - found = this_object; - } - } - } - - else // check ALL objects - { - found = gPipeline.lineSegmentIntersectInHUD(mouse_hud_start, mouse_hud_end, pick_transparent, - face_hit, intersection, uv, normal, binormal); - - if (!found) // if not found in HUD, look in world: - - { - found = gPipeline.lineSegmentIntersectInWorld(mouse_world_start, mouse_world_end, pick_transparent, - face_hit, intersection, uv, normal, binormal); - } - - } - - return found; -} - -// Returns unit vector relative to camera -// indicating direction of point on screen x,y -LLVector3 LLViewerWindow::mouseDirectionGlobal(const S32 x, const S32 y) const -{ - // find vertical field of view - F32 fov = LLViewerCamera::getInstance()->getView(); - - // find world view center in scaled ui coordinates - F32 center_x = getWorldViewRectScaled().getCenterX(); - F32 center_y = getWorldViewRectScaled().getCenterY(); - - // calculate pixel distance to screen - F32 distance = ((F32)getWorldViewHeightScaled() * 0.5f) / (tan(fov / 2.f)); - - // calculate click point relative to middle of screen - F32 click_x = x - center_x; - F32 click_y = y - center_y; - - // compute mouse vector - LLVector3 mouse_vector = distance * LLViewerCamera::getInstance()->getAtAxis() - - click_x * LLViewerCamera::getInstance()->getLeftAxis() - + click_y * LLViewerCamera::getInstance()->getUpAxis(); - - mouse_vector.normVec(); - - return mouse_vector; -} - -LLVector3 LLViewerWindow::mousePointHUD(const S32 x, const S32 y) const -{ - // find screen resolution - S32 height = getWorldViewHeightScaled(); - - // find world view center - F32 center_x = getWorldViewRectScaled().getCenterX(); - F32 center_y = getWorldViewRectScaled().getCenterY(); - - // remap with uniform scale (1/height) so that top is -0.5, bottom is +0.5 - F32 hud_x = -((F32)x - center_x) / height; - F32 hud_y = ((F32)y - center_y) / height; - - return LLVector3(0.f, hud_x/gAgentCamera.mHUDCurZoom, hud_y/gAgentCamera.mHUDCurZoom); -} - -// Returns unit vector relative to camera in camera space -// indicating direction of point on screen x,y -LLVector3 LLViewerWindow::mouseDirectionCamera(const S32 x, const S32 y) const -{ - // find vertical field of view - F32 fov_height = LLViewerCamera::getInstance()->getView(); - F32 fov_width = fov_height * LLViewerCamera::getInstance()->getAspect(); - - // find screen resolution - S32 height = getWorldViewHeightScaled(); - S32 width = getWorldViewWidthScaled(); - - // find world view center - F32 center_x = getWorldViewRectScaled().getCenterX(); - F32 center_y = getWorldViewRectScaled().getCenterY(); - - // calculate click point relative to middle of screen - F32 click_x = (((F32)x - center_x) / (F32)width) * fov_width * -1.f; - F32 click_y = (((F32)y - center_y) / (F32)height) * fov_height; - - // compute mouse vector - LLVector3 mouse_vector = LLVector3(0.f, 0.f, -1.f); - LLQuaternion mouse_rotate; - mouse_rotate.setQuat(click_y, click_x, 0.f); - - mouse_vector = mouse_vector * mouse_rotate; - // project to z = -1 plane; - mouse_vector = mouse_vector * (-1.f / mouse_vector.mV[VZ]); - - return mouse_vector; -} - - - -BOOL LLViewerWindow::mousePointOnPlaneGlobal(LLVector3d& point, const S32 x, const S32 y, - const LLVector3d &plane_point_global, - const LLVector3 &plane_normal_global) -{ - LLVector3d mouse_direction_global_d; - - mouse_direction_global_d.setVec(mouseDirectionGlobal(x,y)); - LLVector3d plane_normal_global_d; - plane_normal_global_d.setVec(plane_normal_global); - F64 plane_mouse_dot = (plane_normal_global_d * mouse_direction_global_d); - LLVector3d plane_origin_camera_rel = plane_point_global - gAgentCamera.getCameraPositionGlobal(); - F64 mouse_look_at_scale = (plane_normal_global_d * plane_origin_camera_rel) - / plane_mouse_dot; - if (llabs(plane_mouse_dot) < 0.00001) - { - // if mouse is parallel to plane, return closest point on line through plane origin - // that is parallel to camera plane by scaling mouse direction vector - // by distance to plane origin, modulated by deviation of mouse direction from plane origin - LLVector3d plane_origin_dir = plane_origin_camera_rel; - plane_origin_dir.normVec(); - - mouse_look_at_scale = plane_origin_camera_rel.magVec() / (plane_origin_dir * mouse_direction_global_d); - } - - point = gAgentCamera.getCameraPositionGlobal() + mouse_look_at_scale * mouse_direction_global_d; - - return mouse_look_at_scale > 0.0; -} - - -// Returns global position -BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d *land_position_global) -{ - LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y); - F32 mouse_dir_scale; - BOOL hit_land = FALSE; - LLViewerRegion *regionp; - F32 land_z; - const F32 FIRST_PASS_STEP = 1.0f; // meters - const F32 SECOND_PASS_STEP = 0.1f; // meters - LLVector3d camera_pos_global; - - camera_pos_global = gAgentCamera.getCameraPositionGlobal(); - LLVector3d probe_point_global; - LLVector3 probe_point_region; - - // walk forwards to find the point - for (mouse_dir_scale = FIRST_PASS_STEP; mouse_dir_scale < gAgentCamera.mDrawDistance; mouse_dir_scale += FIRST_PASS_STEP) - { - LLVector3d mouse_direction_global_d; - mouse_direction_global_d.setVec(mouse_direction_global * mouse_dir_scale); - probe_point_global = camera_pos_global + mouse_direction_global_d; - - regionp = LLWorld::getInstance()->resolveRegionGlobal(probe_point_region, probe_point_global); - - if (!regionp) - { - // ...we're outside the world somehow - continue; - } - - S32 i = (S32) (probe_point_region.mV[VX]/regionp->getLand().getMetersPerGrid()); - S32 j = (S32) (probe_point_region.mV[VY]/regionp->getLand().getMetersPerGrid()); - S32 grids_per_edge = (S32) regionp->getLand().mGridsPerEdge; - if ((i >= grids_per_edge) || (j >= grids_per_edge)) - { - //llinfos << "LLViewerWindow::mousePointOnLand probe_point is out of region" << llendl; - continue; - } - - land_z = regionp->getLand().resolveHeightRegion(probe_point_region); - - //llinfos << "mousePointOnLand initial z " << land_z << llendl; - - if (probe_point_region.mV[VZ] < land_z) - { - // ...just went under land - - // cout << "under land at " << probe_point << " scale " << mouse_vec_scale << endl; - - hit_land = TRUE; - break; - } - } - - - if (hit_land) - { - // Don't go more than one step beyond where we stopped above. - // This can't just be "mouse_vec_scale" because floating point error - // will stop the loop before the last increment.... X - 1.0 + 0.1 + 0.1 + ... + 0.1 != X - F32 stop_mouse_dir_scale = mouse_dir_scale + FIRST_PASS_STEP; - - // take a step backwards, then walk forwards again to refine position - for ( mouse_dir_scale -= FIRST_PASS_STEP; mouse_dir_scale <= stop_mouse_dir_scale; mouse_dir_scale += SECOND_PASS_STEP) - { - LLVector3d mouse_direction_global_d; - mouse_direction_global_d.setVec(mouse_direction_global * mouse_dir_scale); - probe_point_global = camera_pos_global + mouse_direction_global_d; - - regionp = LLWorld::getInstance()->resolveRegionGlobal(probe_point_region, probe_point_global); - - if (!regionp) - { - // ...we're outside the world somehow - continue; - } - - /* - i = (S32) (local_probe_point.mV[VX]/regionp->getLand().getMetersPerGrid()); - j = (S32) (local_probe_point.mV[VY]/regionp->getLand().getMetersPerGrid()); - if ((i >= regionp->getLand().mGridsPerEdge) || (j >= regionp->getLand().mGridsPerEdge)) - { - // llinfos << "LLViewerWindow::mousePointOnLand probe_point is out of region" << llendl; - continue; - } - land_z = regionp->getLand().mSurfaceZ[ i + j * (regionp->getLand().mGridsPerEdge) ]; - */ - - land_z = regionp->getLand().resolveHeightRegion(probe_point_region); - - //llinfos << "mousePointOnLand refine z " << land_z << llendl; - - if (probe_point_region.mV[VZ] < land_z) - { - // ...just went under land again - - *land_position_global = probe_point_global; - return TRUE; - } - } - } - - return FALSE; -} - -// Saves an image to the harddrive as "SnapshotX" where X >= 1. -BOOL LLViewerWindow::saveImageNumbered(LLImageFormatted *image) -{ - if (!image) - { - return FALSE; - } - - LLFilePicker::ESaveFilter pick_type; - std::string extension("." + image->getExtension()); - if (extension == ".j2c") - pick_type = LLFilePicker::FFSAVE_J2C; - else if (extension == ".bmp") - pick_type = LLFilePicker::FFSAVE_BMP; - else if (extension == ".jpg") - pick_type = LLFilePicker::FFSAVE_JPEG; - else if (extension == ".png") - pick_type = LLFilePicker::FFSAVE_PNG; - else if (extension == ".tga") - pick_type = LLFilePicker::FFSAVE_TGA; - else - pick_type = LLFilePicker::FFSAVE_ALL; // ??? - - // Get a base file location if needed. - if ( ! isSnapshotLocSet()) - { - std::string proposed_name( sSnapshotBaseName ); - - // getSaveFile will append an appropriate extension to the proposed name, based on the ESaveFilter constant passed in. - - // pick a directory in which to save - LLFilePicker& picker = LLFilePicker::instance(); - if (!picker.getSaveFile(pick_type, proposed_name)) - { - // Clicked cancel - return FALSE; - } - - // Copy the directory + file name - std::string filepath = picker.getFirstFile(); - - LLViewerWindow::sSnapshotBaseName = gDirUtilp->getBaseFileName(filepath, true); - LLViewerWindow::sSnapshotDir = gDirUtilp->getDirName(filepath); - } - - // Look for an unused file name - std::string filepath; - S32 i = 1; - S32 err = 0; - - do - { - filepath = sSnapshotDir; - filepath += gDirUtilp->getDirDelimiter(); - filepath += sSnapshotBaseName; - filepath += llformat("_%.3d",i); - filepath += extension; - - llstat stat_info; - err = LLFile::stat( filepath, &stat_info ); - i++; - } - while( -1 != err ); // search until the file is not found (i.e., stat() gives an error). - - return image->save(filepath); -} - -void LLViewerWindow::resetSnapshotLoc() -{ - sSnapshotDir.clear(); -} - -static S32 BORDERHEIGHT = 0; -static S32 BORDERWIDTH = 0; - -// static -void LLViewerWindow::movieSize(S32 new_width, S32 new_height) -{ - LLCoordScreen size; - gViewerWindow->mWindow->getSize(&size); - if ( (size.mX != new_width + BORDERWIDTH) - ||(size.mY != new_height + BORDERHEIGHT)) - { - // use actual display dimensions, not virtual UI dimensions - S32 x = gViewerWindow->getWindowWidthRaw(); - S32 y = gViewerWindow->getWindowHeightRaw(); - BORDERWIDTH = size.mX - x; - BORDERHEIGHT = size.mY- y; - LLCoordScreen new_size(new_width + BORDERWIDTH, - new_height + BORDERHEIGHT); - gViewerWindow->mWindow->setSize(new_size); - } -} - -BOOL LLViewerWindow::saveSnapshot( const std::string& filepath, S32 image_width, S32 image_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type) -{ - llinfos << "Saving snapshot to: " << filepath << llendl; - - LLPointer<LLImageRaw> raw = new LLImageRaw; - BOOL success = rawSnapshot(raw, image_width, image_height, TRUE, FALSE, show_ui, do_rebuild); - - if (success) - { - LLPointer<LLImageBMP> bmp_image = new LLImageBMP; - success = bmp_image->encode(raw, 0.0f); - if( success ) - { - success = bmp_image->save(filepath); - } - else - { - llwarns << "Unable to encode bmp snapshot" << llendl; - } - } - else - { - llwarns << "Unable to capture raw snapshot" << llendl; - } - - return success; -} - - -void LLViewerWindow::playSnapshotAnimAndSound() -{ - if (gSavedSettings.getBOOL("QuietSnapshotsToDisk")) - { - return; - } - gAgent.sendAnimationRequest(ANIM_AGENT_SNAPSHOT, ANIM_REQUEST_START); - send_sound_trigger(LLUUID(gSavedSettings.getString("UISndSnapshot")), 1.0f); -} - -BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type) -{ - return rawSnapshot(raw, preview_width, preview_height, FALSE, FALSE, show_ui, do_rebuild, type); -} - -// Saves the image from the screen to the specified filename and path. -BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, - BOOL keep_window_aspect, BOOL is_texture, BOOL show_ui, BOOL do_rebuild, ESnapshotType type, S32 max_size) -{ - if (!raw) - { - return FALSE; - } - - // PRE SNAPSHOT - gDisplaySwapBuffers = FALSE; - - glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - setCursor(UI_CURSOR_WAIT); - - // Hide all the UI widgets first and draw a frame - BOOL prev_draw_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI) ? TRUE : FALSE; - - show_ui = show_ui ? TRUE : FALSE; - - if ( prev_draw_ui != show_ui) - { - LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI); - } - - BOOL hide_hud = !gSavedSettings.getBOOL("RenderHUDInSnapshot") && LLPipeline::sShowHUDAttachments; - if (hide_hud) - { - LLPipeline::sShowHUDAttachments = FALSE; - } - - // if not showing ui, use full window to render world view - updateWorldViewRect(!show_ui); - - // Copy screen to a buffer - // crop sides or top and bottom, if taking a snapshot of different aspect ratio - // from window - LLRect window_rect = show_ui ? getWindowRectRaw() : getWorldViewRectRaw(); - - S32 snapshot_width = window_rect.getWidth(); - S32 snapshot_height = window_rect.getHeight(); - // SNAPSHOT - S32 window_width = snapshot_width; - S32 window_height = snapshot_height; - - if (show_ui) - { - image_width = llmin(image_width, window_width); - image_height = llmin(image_height, window_height); - } - - F32 scale_factor = 1.0f ; - if(!keep_window_aspect) //image cropping - { - F32 ratio = llmin( (F32)window_width / image_width , (F32)window_height / image_height) ; - snapshot_width = (S32)(ratio * image_width) ; - snapshot_height = (S32)(ratio * image_height) ; - scale_factor = llmax(1.0f, 1.0f / ratio) ; - } - else //the scene(window) proportion needs to be maintained. - { - if(image_width > window_width || image_height > window_height) //need to enlarge the scene - { - F32 ratio = llmin( (F32)window_width / image_width , (F32)window_height / image_height) ; - snapshot_width = (S32)(ratio * image_width) ; - snapshot_height = (S32)(ratio * image_height) ; - scale_factor = llmax(1.0f, 1.0f / ratio) ; - } - } - - if (show_ui && scale_factor > 1.f) - { - llwarns << "over scaling UI not supported." << llendl; - } - - S32 buffer_x_offset = llfloor(((window_width - snapshot_width) * scale_factor) / 2.f); - S32 buffer_y_offset = llfloor(((window_height - snapshot_height) * scale_factor) / 2.f); - - S32 image_buffer_x = llfloor(snapshot_width*scale_factor) ; - S32 image_buffer_y = llfloor(snapshot_height *scale_factor) ; - - if(image_buffer_x > max_size || image_buffer_y > max_size) //boundary check to avoid memory overflow - { - scale_factor *= llmin((F32)max_size / image_buffer_x, (F32)max_size / image_buffer_y) ; - image_buffer_x = llfloor(snapshot_width*scale_factor) ; - image_buffer_y = llfloor(snapshot_height *scale_factor) ; - } - if(image_buffer_x > 0 && image_buffer_y > 0) - { - raw->resize(image_buffer_x, image_buffer_y, 3); - } - else - { - return FALSE ; - } - if(raw->isBufferInvalid()) - { - return FALSE ; - } - - BOOL high_res = scale_factor >= 2.f; // Font scaling is slow, only do so if rez is much higher - if (high_res && show_ui) - { - llwarns << "High res UI snapshot not supported. " << llendl; - /*send_agent_pause(); - //rescale fonts - initFonts(scale_factor); - LLHUDObject::reshapeAll();*/ - } - - S32 output_buffer_offset_y = 0; - - F32 depth_conversion_factor_1 = (LLViewerCamera::getInstance()->getFar() + LLViewerCamera::getInstance()->getNear()) / (2.f * LLViewerCamera::getInstance()->getFar() * LLViewerCamera::getInstance()->getNear()); - F32 depth_conversion_factor_2 = (LLViewerCamera::getInstance()->getFar() - LLViewerCamera::getInstance()->getNear()) / (2.f * LLViewerCamera::getInstance()->getFar() * LLViewerCamera::getInstance()->getNear()); - - gObjectList.generatePickList(*LLViewerCamera::getInstance()); - - for (int subimage_y = 0; subimage_y < scale_factor; ++subimage_y) - { - S32 subimage_y_offset = llclamp(buffer_y_offset - (subimage_y * window_height), 0, window_height);; - // handle fractional columns - U32 read_height = llmax(0, (window_height - subimage_y_offset) - - llmax(0, (window_height * (subimage_y + 1)) - (buffer_y_offset + raw->getHeight()))); - - S32 output_buffer_offset_x = 0; - for (int subimage_x = 0; subimage_x < scale_factor; ++subimage_x) - { - gDisplaySwapBuffers = FALSE; - gDepthDirty = TRUE; - - const U32 subfield = subimage_x+(subimage_y*llceil(scale_factor)); - - if (LLPipeline::sRenderDeferred) - { - display(do_rebuild, scale_factor, subfield, TRUE); - } - else - { - display(do_rebuild, scale_factor, subfield, TRUE); - // Required for showing the GUI in snapshots and performing bloom composite overlay - // Call even if show_ui is FALSE - render_ui(scale_factor, subfield); - } - - S32 subimage_x_offset = llclamp(buffer_x_offset - (subimage_x * window_width), 0, window_width); - // handle fractional rows - U32 read_width = llmax(0, (window_width - subimage_x_offset) - - llmax(0, (window_width * (subimage_x + 1)) - (buffer_x_offset + raw->getWidth()))); - for(U32 out_y = 0; out_y < read_height ; out_y++) - { - S32 output_buffer_offset = ( - (out_y * (raw->getWidth())) // ...plus iterated y... - + (window_width * subimage_x) // ...plus subimage start in x... - + (raw->getWidth() * window_height * subimage_y) // ...plus subimage start in y... - - output_buffer_offset_x // ...minus buffer padding x... - - (output_buffer_offset_y * (raw->getWidth())) // ...minus buffer padding y... - ) * raw->getComponents(); - - // Ping the wathdog thread every 100 lines to keep us alive (arbitrary number, feel free to change) - if (out_y % 100 == 0) - { - LLAppViewer::instance()->pingMainloopTimeout("LLViewerWindow::rawSnapshot"); - } - - if (type == SNAPSHOT_TYPE_COLOR) - { - glReadPixels( - subimage_x_offset, out_y + subimage_y_offset, - read_width, 1, - GL_RGB, GL_UNSIGNED_BYTE, - raw->getData() + output_buffer_offset - ); - } - else // SNAPSHOT_TYPE_DEPTH - { - LLPointer<LLImageRaw> depth_line_buffer = new LLImageRaw(read_width, 1, sizeof(GL_FLOAT)); // need to store floating point values - glReadPixels( - subimage_x_offset, out_y + subimage_y_offset, - read_width, 1, - GL_DEPTH_COMPONENT, GL_FLOAT, - depth_line_buffer->getData()// current output pixel is beginning of buffer... - ); - - for (S32 i = 0; i < (S32)read_width; i++) - { - F32 depth_float = *(F32*)(depth_line_buffer->getData() + (i * sizeof(F32))); - - F32 linear_depth_float = 1.f / (depth_conversion_factor_1 - (depth_float * depth_conversion_factor_2)); - U8 depth_byte = F32_to_U8(linear_depth_float, LLViewerCamera::getInstance()->getNear(), LLViewerCamera::getInstance()->getFar()); - //write converted scanline out to result image - for(S32 j = 0; j < raw->getComponents(); j++) - { - *(raw->getData() + output_buffer_offset + (i * raw->getComponents()) + j) = depth_byte; - } - } - } - } - output_buffer_offset_x += subimage_x_offset; - stop_glerror(); - } - output_buffer_offset_y += subimage_y_offset; - } - - gDisplaySwapBuffers = FALSE; - gDepthDirty = TRUE; - - // POST SNAPSHOT - if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) - { - LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI); - } - - if (hide_hud) - { - LLPipeline::sShowHUDAttachments = TRUE; - } - - /*if (high_res) - { - initFonts(1.f); - LLHUDObject::reshapeAll(); - }*/ - - // Pre-pad image to number of pixels such that the line length is a multiple of 4 bytes (for BMP encoding) - // Note: this formula depends on the number of components being 3. Not obvious, but it's correct. - image_width += (image_width * 3) % 4; - - BOOL ret = TRUE ; - // Resize image - if(llabs(image_width - image_buffer_x) > 4 || llabs(image_height - image_buffer_y) > 4) - { - ret = raw->scale( image_width, image_height ); - } - else if(image_width != image_buffer_x || image_height != image_buffer_y) - { - ret = raw->scale( image_width, image_height, FALSE ); - } - - - setCursor(UI_CURSOR_ARROW); - - if (do_rebuild) - { - // If we had to do a rebuild, that means that the lists of drawables to be rendered - // was empty before we started. - // Need to reset these, otherwise we call state sort on it again when render gets called the next time - // and we stand a good chance of crashing on rebuild because the render drawable arrays have multiple copies of - // objects on them. - gPipeline.resetDrawOrders(); - } - - if (high_res) - { - send_agent_resume(); - } - - return ret; -} - -void LLViewerWindow::destroyWindow() -{ - if (mWindow) - { - LLWindowManager::destroyWindow(mWindow); - } - mWindow = NULL; -} - - -void LLViewerWindow::drawMouselookInstructions() -{ - // Draw instructions for mouselook ("Press ESC to return to World View" partially transparent at the bottom of the screen.) - const std::string instructions = LLTrans::getString("LeaveMouselook"); - const LLFontGL* font = LLFontGL::getFont(LLFontDescriptor("SansSerif", "Large", LLFontGL::BOLD)); - - //to be on top of Bottom bar when it is opened - const S32 INSTRUCTIONS_PAD = 50; - - font->renderUTF8( - instructions, 0, - getWorldViewRectScaled().getCenterX(), - getWorldViewRectScaled().mBottom + INSTRUCTIONS_PAD, - LLColor4( 1.0f, 1.0f, 1.0f, 0.5f ), - LLFontGL::HCENTER, LLFontGL::TOP, - LLFontGL::NORMAL,LLFontGL::DROP_SHADOW); -} - -void* LLViewerWindow::getPlatformWindow() const -{ - return mWindow->getPlatformWindow(); -} - -void* LLViewerWindow::getMediaWindow() const -{ - return mWindow->getMediaWindow(); -} - -void LLViewerWindow::focusClient() const -{ - return mWindow->focusClient(); -} - -LLRootView* LLViewerWindow::getRootView() const -{ - return mRootView; -} - -LLRect LLViewerWindow::getWorldViewRectScaled() const -{ - return mWorldViewRectScaled; -} - -S32 LLViewerWindow::getWorldViewHeightScaled() const -{ - return mWorldViewRectScaled.getHeight(); -} - -S32 LLViewerWindow::getWorldViewWidthScaled() const -{ - return mWorldViewRectScaled.getWidth(); -} - - -S32 LLViewerWindow::getWorldViewHeightRaw() const -{ - return mWorldViewRectRaw.getHeight(); -} - -S32 LLViewerWindow::getWorldViewWidthRaw() const -{ - return mWorldViewRectRaw.getWidth(); -} - -S32 LLViewerWindow::getWindowHeightScaled() const -{ - return mWindowRectScaled.getHeight(); -} - -S32 LLViewerWindow::getWindowWidthScaled() const -{ - return mWindowRectScaled.getWidth(); -} - -S32 LLViewerWindow::getWindowHeightRaw() const -{ - return mWindowRectRaw.getHeight(); -} - -S32 LLViewerWindow::getWindowWidthRaw() const -{ - return mWindowRectRaw.getWidth(); -} - -void LLViewerWindow::setup2DRender() -{ - // setup ortho camera - gl_state_for_2d(mWindowRectRaw.getWidth(), mWindowRectRaw.getHeight()); - setup2DViewport(); -} - -void LLViewerWindow::setup2DViewport(S32 x_offset, S32 y_offset) -{ - gGLViewport[0] = mWindowRectRaw.mLeft + x_offset; - gGLViewport[1] = mWindowRectRaw.mBottom + y_offset; - gGLViewport[2] = mWindowRectRaw.getWidth(); - gGLViewport[3] = mWindowRectRaw.getHeight(); - glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); -} - - -void LLViewerWindow::setup3DRender() -{ - // setup perspective camera - LLViewerCamera::getInstance()->setPerspective(NOT_FOR_SELECTION, mWorldViewRectRaw.mLeft, mWorldViewRectRaw.mBottom, mWorldViewRectRaw.getWidth(), mWorldViewRectRaw.getHeight(), FALSE, LLViewerCamera::getInstance()->getNear(), MAX_FAR_CLIP*2.f); - setup3DViewport(); -} - -void LLViewerWindow::setup3DViewport(S32 x_offset, S32 y_offset) -{ - gGLViewport[0] = mWorldViewRectRaw.mLeft + x_offset; - gGLViewport[1] = mWorldViewRectRaw.mBottom + y_offset; - gGLViewport[2] = mWorldViewRectRaw.getWidth(); - gGLViewport[3] = mWorldViewRectRaw.getHeight(); - glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); -} - -void LLViewerWindow::setShowProgress(const BOOL show) -{ - if (mProgressView) - { - mProgressView->setVisible(show); - } -} - -BOOL LLViewerWindow::getShowProgress() const -{ - return (mProgressView && mProgressView->getVisible()); -} - -void LLViewerWindow::setProgressString(const std::string& string) -{ - if (mProgressView) - { - mProgressView->setText(string); - } -} - -void LLViewerWindow::setProgressMessage(const std::string& msg) -{ - if(mProgressView) - { - mProgressView->setMessage(msg); - } -} - -void LLViewerWindow::setProgressPercent(const F32 percent) -{ - if (mProgressView) - { - mProgressView->setPercent(percent); - } -} - -void LLViewerWindow::setProgressCancelButtonVisible( BOOL b, const std::string& label ) -{ - if (mProgressView) - { - mProgressView->setCancelButtonVisible( b, label ); - } -} - - -LLProgressView *LLViewerWindow::getProgressView() const -{ - return mProgressView; -} - -void LLViewerWindow::dumpState() -{ - llinfos << "LLViewerWindow Active " << S32(mActive) << llendl; - llinfos << "mWindow visible " << S32(mWindow->getVisible()) - << " minimized " << S32(mWindow->getMinimized()) - << llendl; -} - -void LLViewerWindow::stopGL(BOOL save_state) -{ - //Note: --bao - //if not necessary, do not change the order of the function calls in this function. - //if change something, make sure it will not break anything. - //especially be careful to put anything behind gTextureList.destroyGL(save_state); - if (!gGLManager.mIsDisabled) - { - llinfos << "Shutting down GL..." << llendl; - - // Pause texture decode threads (will get unpaused during main loop) - LLAppViewer::getTextureCache()->pause(); - LLAppViewer::getImageDecodeThread()->pause(); - LLAppViewer::getTextureFetch()->pause(); - - gSky.destroyGL(); - stop_glerror(); - - LLManipTranslate::destroyGL() ; - stop_glerror(); - - gBumpImageList.destroyGL(); - stop_glerror(); - - LLFontGL::destroyAllGL(); - stop_glerror(); - - LLVOAvatar::destroyGL(); - stop_glerror(); - - LLViewerDynamicTexture::destroyGL(); - stop_glerror(); - - if (gPipeline.isInit()) - { - gPipeline.destroyGL(); - } - - gCone.cleanupGL(); - gBox.cleanupGL(); - gSphere.cleanupGL(); - gCylinder.cleanupGL(); - - if(gPostProcess) - { - gPostProcess->invalidate(); - } - - gTextureList.destroyGL(save_state); - stop_glerror(); - - gGLManager.mIsDisabled = TRUE; - stop_glerror(); - - llinfos << "Remaining allocated texture memory: " << LLImageGL::sGlobalTextureMemoryInBytes << " bytes" << llendl; - } -} - -void LLViewerWindow::restoreGL(const std::string& progress_message) -{ - //Note: --bao - //if not necessary, do not change the order of the function calls in this function. - //if change something, make sure it will not break anything. - //especially, be careful to put something before gTextureList.restoreGL(); - if (gGLManager.mIsDisabled) - { - llinfos << "Restoring GL..." << llendl; - gGLManager.mIsDisabled = FALSE; - - initGLDefaults(); - LLGLState::restoreGL(); - - gTextureList.restoreGL(); - - // for future support of non-square pixels, and fonts that are properly stretched - //LLFontGL::destroyDefaultFonts(); - initFonts(); - - gSky.restoreGL(); - gPipeline.restoreGL(); - LLDrawPoolWater::restoreGL(); - LLManipTranslate::restoreGL(); - - gBumpImageList.restoreGL(); - LLViewerDynamicTexture::restoreGL(); - LLVOAvatar::restoreGL(); - - gResizeScreenTexture = TRUE; - gWindowResized = TRUE; - - if (isAgentAvatarValid() && !gAgentAvatarp->isUsingBakedTextures()) - { - LLVisualParamHint::requestHintUpdates(); - } - - if (!progress_message.empty()) - { - gRestoreGLTimer.reset(); - gRestoreGL = TRUE; - setShowProgress(TRUE); - setProgressString(progress_message); - } - llinfos << "...Restoring GL done" << llendl; - if(!LLAppViewer::instance()->restoreErrorTrap()) - { - llwarns << " Someone took over my signal/exception handler (post restoreGL)!" << llendl; - } - - } -} - -void LLViewerWindow::initFonts(F32 zoom_factor) -{ - LLFontGL::destroyAllGL(); - // Initialize with possibly different zoom factor - LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"), - mDisplayScale.mV[VX] * zoom_factor, - mDisplayScale.mV[VY] * zoom_factor, - gDirUtilp->getAppRODataDir(), - LLUI::getXUIPaths()); - // Force font reloads, which can be very slow - LLFontGL::loadDefaultFonts(); -} - -void LLViewerWindow::requestResolutionUpdate() -{ - mResDirty = true; -} - -void LLViewerWindow::checkSettings() -{ - if (mStatesDirty) - { - gGL.refreshState(); - LLViewerShaderMgr::instance()->setShaders(); - mStatesDirty = false; - } - - // We want to update the resolution AFTER the states getting refreshed not before. - if (mResDirty) - { - reshape(getWindowWidthRaw(), getWindowHeightRaw()); - mResDirty = false; - } -} - -void LLViewerWindow::restartDisplay(BOOL show_progress_bar) -{ - llinfos << "Restaring GL" << llendl; - stopGL(); - if (show_progress_bar) - { - restoreGL(LLTrans::getString("ProgressChangingResolution")); - } - else - { - restoreGL(); - } -} - -BOOL LLViewerWindow::changeDisplaySettings(LLCoordScreen size, BOOL disable_vsync, BOOL show_progress_bar) -{ - //BOOL was_maximized = gSavedSettings.getBOOL("WindowMaximized"); - - //gResizeScreenTexture = TRUE; - - //U32 fsaa = gSavedSettings.getU32("RenderFSAASamples"); - //U32 old_fsaa = mWindow->getFSAASamples(); - - // if not maximized, use the request size - if (!mWindow->getMaximized()) - { - mWindow->setSize(size); - } - - //if (fsaa == old_fsaa) - { - return TRUE; - } - -/* - - // Close floaters that don't handle settings change - LLFloaterReg::hideInstance("snapshot"); - - BOOL result_first_try = FALSE; - BOOL result_second_try = FALSE; - - LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus(); - send_agent_pause(); - llinfos << "Stopping GL during changeDisplaySettings" << llendl; - stopGL(); - mIgnoreActivate = TRUE; - LLCoordScreen old_size; - LLCoordScreen old_pos; - mWindow->getSize(&old_size); - - //mWindow->setFSAASamples(fsaa); - - result_first_try = mWindow->switchContext(false, size, disable_vsync); - if (!result_first_try) - { - // try to switch back - //mWindow->setFSAASamples(old_fsaa); - result_second_try = mWindow->switchContext(false, old_size, disable_vsync); - - if (!result_second_try) - { - // we are stuck...try once again with a minimal resolution? - send_agent_resume(); - mIgnoreActivate = FALSE; - return FALSE; - } - } - send_agent_resume(); - - llinfos << "Restoring GL during resolution change" << llendl; - if (show_progress_bar) - { - restoreGL(LLTrans::getString("ProgressChangingResolution")); - } - else - { - restoreGL(); - } - - if (!result_first_try) - { - LLSD args; - args["RESX"] = llformat("%d",size.mX); - args["RESY"] = llformat("%d",size.mY); - LLNotificationsUtil::add("ResolutionSwitchFail", args); - size = old_size; // for reshape below - } - - BOOL success = result_first_try || result_second_try; - - if (success) - { - // maximize window if was maximized, else reposition - if (was_maximized) - { - mWindow->maximize(); - } - else - { - S32 windowX = gSavedSettings.getS32("WindowX"); - S32 windowY = gSavedSettings.getS32("WindowY"); - - mWindow->setPosition(LLCoordScreen ( windowX, windowY ) ); - } - } - - mIgnoreActivate = FALSE; - gFocusMgr.setKeyboardFocus(keyboard_focus); - - return success; - - */ -} - -F32 LLViewerWindow::getWorldViewAspectRatio() const -{ - F32 world_aspect = (F32)mWorldViewRectRaw.getWidth() / (F32)mWorldViewRectRaw.getHeight(); - return world_aspect; -} - -void LLViewerWindow::calcDisplayScale() -{ - F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor"); - LLVector2 display_scale; - display_scale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f)); - display_scale *= ui_scale_factor; - - // limit minimum display scale - if (display_scale.mV[VX] < MIN_DISPLAY_SCALE || display_scale.mV[VY] < MIN_DISPLAY_SCALE) - { - display_scale *= MIN_DISPLAY_SCALE / llmin(display_scale.mV[VX], display_scale.mV[VY]); - } - - if (display_scale != mDisplayScale) - { - llinfos << "Setting display scale to " << display_scale << llendl; - - mDisplayScale = display_scale; - // Init default fonts - initFonts(); - } -} - -//static -LLRect LLViewerWindow::calcScaledRect(const LLRect & rect, const LLVector2& display_scale) -{ - LLRect res = rect; - res.mLeft = llround((F32)res.mLeft / display_scale.mV[VX]); - res.mRight = llround((F32)res.mRight / display_scale.mV[VX]); - res.mBottom = llround((F32)res.mBottom / display_scale.mV[VY]); - res.mTop = llround((F32)res.mTop / display_scale.mV[VY]); - - return res; -} - -S32 LLViewerWindow::getChatConsoleBottomPad() -{ - S32 offset = 0; - - if(LLBottomTray::instanceExists()) - offset += LLBottomTray::getInstance()->getRect().getHeight(); - - return offset; -} - -LLRect LLViewerWindow::getChatConsoleRect() -{ - LLRect full_window(0, getWindowHeightScaled(), getWindowWidthScaled(), 0); - LLRect console_rect = full_window; - - const S32 CONSOLE_PADDING_TOP = 24; - const S32 CONSOLE_PADDING_LEFT = 24; - const S32 CONSOLE_PADDING_RIGHT = 10; - - console_rect.mTop -= CONSOLE_PADDING_TOP; - console_rect.mBottom += getChatConsoleBottomPad(); - - console_rect.mLeft += CONSOLE_PADDING_LEFT; - - static const BOOL CHAT_FULL_WIDTH = gSavedSettings.getBOOL("ChatFullWidth"); - - if (CHAT_FULL_WIDTH) - { - console_rect.mRight -= CONSOLE_PADDING_RIGHT; - } - else - { - // Make console rect somewhat narrow so having inventory open is - // less of a problem. - console_rect.mRight = console_rect.mLeft + 2 * getWindowWidthScaled() / 3; - } - - return console_rect; -} -//---------------------------------------------------------------------------- - - -//static -bool LLViewerWindow::onAlert(const LLSD& notify) -{ - LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID()); - - if (gNoRender) - { - llinfos << "Alert: " << notification->getName() << llendl; - notification->respond(LLSD::emptyMap()); - LLNotifications::instance().cancel(notification); - return false; - } - - // If we're in mouselook, the mouse is hidden and so the user can't click - // the dialog buttons. In that case, change to First Person instead. - if( gAgentCamera.cameraMouselook() ) - { - gAgentCamera.changeCameraToDefault(); - } - return false; -} - -//////////////////////////////////////////////////////////////////////////// -// -// LLPickInfo -// -LLPickInfo::LLPickInfo() - : mKeyMask(MASK_NONE), - mPickCallback(NULL), - mPickType(PICK_INVALID), - mWantSurfaceInfo(FALSE), - mObjectFace(-1), - mUVCoords(-1.f, -1.f), - mSTCoords(-1.f, -1.f), - mXYCoords(-1, -1), - mIntersection(), - mNormal(), - mBinormal(), - mHUDIcon(NULL), - mPickTransparent(FALSE) -{ -} - -LLPickInfo::LLPickInfo(const LLCoordGL& mouse_pos, - MASK keyboard_mask, - BOOL pick_transparent, - BOOL pick_uv_coords, - void (*pick_callback)(const LLPickInfo& pick_info)) - : mMousePt(mouse_pos), - mKeyMask(keyboard_mask), - mPickCallback(pick_callback), - mPickType(PICK_INVALID), - mWantSurfaceInfo(pick_uv_coords), - mObjectFace(-1), - mUVCoords(-1.f, -1.f), - mSTCoords(-1.f, -1.f), - mXYCoords(-1, -1), - mNormal(), - mBinormal(), - mHUDIcon(NULL), - mPickTransparent(pick_transparent) -{ -} - -void LLPickInfo::fetchResults() -{ - - S32 face_hit = -1; - LLVector3 intersection, normal, binormal; - LLVector2 uv; - - LLHUDIcon* hit_icon = gViewerWindow->cursorIntersectIcon(mMousePt.mX, mMousePt.mY, 512.f, &intersection); - - F32 icon_dist = 0.f; - if (hit_icon) - { - icon_dist = (LLViewerCamera::getInstance()->getOrigin()-intersection).magVec(); - } - LLViewerObject* hit_object = gViewerWindow->cursorIntersect(mMousePt.mX, mMousePt.mY, 512.f, - NULL, -1, mPickTransparent, &face_hit, - &intersection, &uv, &normal, &binormal); - - mPickPt = mMousePt; - - U32 te_offset = face_hit > -1 ? face_hit : 0; - - //unproject relative clicked coordinate from window coordinate using GL - - LLViewerObject* objectp = hit_object; - - if (hit_icon && - (!objectp || - icon_dist < (LLViewerCamera::getInstance()->getOrigin()-intersection).magVec())) - { - // was this name referring to a hud icon? - mHUDIcon = hit_icon; - mPickType = PICK_ICON; - mPosGlobal = mHUDIcon->getPositionGlobal(); - } - else if (objectp) - { - if( objectp->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH ) - { - // Hit land - mPickType = PICK_LAND; - mObjectID.setNull(); // land has no id - - // put global position into land_pos - LLVector3d land_pos; - if (!gViewerWindow->mousePointOnLandGlobal(mPickPt.mX, mPickPt.mY, &land_pos)) - { - // The selected point is beyond the draw distance or is otherwise - // not selectable. Return before calling mPickCallback(). - return; - } - - // Fudge the land focus a little bit above ground. - mPosGlobal = land_pos + LLVector3d::z_axis * 0.1f; - } - else - { - if(isFlora(objectp)) - { - mPickType = PICK_FLORA; - } - else - { - mPickType = PICK_OBJECT; - } - mObjectOffset = gAgentCamera.calcFocusOffset(objectp, intersection, mPickPt.mX, mPickPt.mY); - mObjectID = objectp->mID; - mObjectFace = (te_offset == NO_FACE) ? -1 : (S32)te_offset; - - mPosGlobal = gAgent.getPosGlobalFromAgent(intersection); - - if (mWantSurfaceInfo) - { - getSurfaceInfo(); - } - } - } - - if (mPickCallback) - { - mPickCallback(*this); - } -} - -LLPointer<LLViewerObject> LLPickInfo::getObject() const -{ - return gObjectList.findObject( mObjectID ); -} - -void LLPickInfo::updateXYCoords() -{ - if (mObjectFace > -1) - { - const LLTextureEntry* tep = getObject()->getTE(mObjectFace); - LLPointer<LLViewerTexture> imagep = LLViewerTextureManager::getFetchedTexture(tep->getID()); - if(mUVCoords.mV[VX] >= 0.f && mUVCoords.mV[VY] >= 0.f && imagep.notNull()) - { - mXYCoords.mX = llround(mUVCoords.mV[VX] * (F32)imagep->getWidth()); - mXYCoords.mY = llround((1.f - mUVCoords.mV[VY]) * (F32)imagep->getHeight()); - } - } -} - -void LLPickInfo::getSurfaceInfo() -{ - // set values to uninitialized - this is what we return if no intersection is found - mObjectFace = -1; - mUVCoords = LLVector2(-1, -1); - mSTCoords = LLVector2(-1, -1); - mXYCoords = LLCoordScreen(-1, -1); - mIntersection = LLVector3(0,0,0); - mNormal = LLVector3(0,0,0); - mBinormal = LLVector3(0,0,0); - - LLViewerObject* objectp = getObject(); - - if (objectp) - { - if (gViewerWindow->cursorIntersect(llround((F32)mMousePt.mX), llround((F32)mMousePt.mY), 1024.f, - objectp, -1, mPickTransparent, - &mObjectFace, - &mIntersection, - &mSTCoords, - &mNormal, - &mBinormal)) - { - // if we succeeded with the intersect above, compute the texture coordinates: - - if (objectp->mDrawable.notNull() && mObjectFace > -1) - { - LLFace* facep = objectp->mDrawable->getFace(mObjectFace); - - mUVCoords = facep->surfaceToTexture(mSTCoords, mIntersection, mNormal); - } - - // and XY coords: - updateXYCoords(); - - } - } -} - - -/* code to get UV via a special UV render - removed in lieu of raycast method -LLVector2 LLPickInfo::pickUV() -{ - LLVector2 result(-1.f, -1.f); - - LLViewerObject* objectp = getObject(); - if (!objectp) - { - return result; - } - - if (mObjectFace > -1 && - objectp->mDrawable.notNull() && objectp->getPCode() == LL_PCODE_VOLUME && - mObjectFace < objectp->mDrawable->getNumFaces()) - { - S32 scaled_x = llround((F32)mPickPt.mX * gViewerWindow->getDisplayScale().mV[VX]); - S32 scaled_y = llround((F32)mPickPt.mY * gViewerWindow->getDisplayScale().mV[VY]); - const S32 UV_PICK_WIDTH = 5; - const S32 UV_PICK_HALF_WIDTH = (UV_PICK_WIDTH - 1) / 2; - U8 uv_pick_buffer[UV_PICK_WIDTH * UV_PICK_WIDTH * 4]; - LLFace* facep = objectp->mDrawable->getFace(mObjectFace); - if (facep) - { - LLGLState scissor_state(GL_SCISSOR_TEST); - scissor_state.enable(); - LLViewerCamera::getInstance()->setPerspective(FOR_SELECTION, scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH, FALSE); - //glViewport(scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH); - glScissor(scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH); - - glClear(GL_DEPTH_BUFFER_BIT); - - facep->renderSelectedUV(); - - glReadPixels(scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH, GL_RGBA, GL_UNSIGNED_BYTE, uv_pick_buffer); - U8* center_pixel = &uv_pick_buffer[4 * ((UV_PICK_WIDTH * UV_PICK_HALF_WIDTH) + UV_PICK_HALF_WIDTH + 1)]; - - result.mV[VX] = (F32)((center_pixel[VGREEN] & 0xf) + (16.f * center_pixel[VRED])) / 4095.f; - result.mV[VY] = (F32)((center_pixel[VGREEN] >> 4) + (16.f * center_pixel[VBLUE])) / 4095.f; - } - } - - return result; -} */ - - -//static -bool LLPickInfo::isFlora(LLViewerObject* object) -{ - if (!object) return false; - - LLPCode pcode = object->getPCode(); - - if( (LL_PCODE_LEGACY_GRASS == pcode) - || (LL_PCODE_LEGACY_TREE == pcode) - || (LL_PCODE_TREE_NEW == pcode)) - { - return true; - } - return false; -} +/**
+ * @file llviewerwindow.cpp
+ * @brief Implementation of the LLViewerWindow class.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llviewerwindow.h"
+
+#if LL_WINDOWS
+#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
+#endif
+
+// system library includes
+#include <stdio.h>
+#include <iostream>
+#include <fstream>
+#include <algorithm>
+
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llfloaterreg.h"
+#include "llpanellogin.h"
+#include "llviewerkeyboard.h"
+#include "llviewermenu.h"
+
+#include "llviewquery.h"
+#include "llxmltree.h"
+#include "llslurl.h"
+//#include "llviewercamera.h"
+#include "llrender.h"
+
+#include "llvoiceclient.h" // for push-to-talk button handling
+
+//
+// TODO: Many of these includes are unnecessary. Remove them.
+//
+
+// linden library includes
+#include "llaudioengine.h" // mute on minimize
+#include "indra_constants.h"
+#include "llassetstorage.h"
+#include "llerrorcontrol.h"
+#include "llfontgl.h"
+#include "llmousehandler.h"
+#include "llrect.h"
+#include "llsky.h"
+#include "llstring.h"
+#include "llui.h"
+#include "lluuid.h"
+#include "llview.h"
+#include "llxfermanager.h"
+#include "message.h"
+#include "object_flags.h"
+#include "lltimer.h"
+#include "timing.h"
+#include "llviewermenu.h"
+#include "lltooltip.h"
+#include "llmediaentry.h"
+#include "llurldispatcher.h"
+
+// newview includes
+#include "llagent.h"
+#include "llbox.h"
+#include "llconsole.h"
+#include "llviewercontrol.h"
+#include "llcylinder.h"
+#include "lldebugview.h"
+#include "lldir.h"
+#include "lldrawable.h"
+#include "lldrawpoolalpha.h"
+#include "lldrawpoolbump.h"
+#include "lldrawpoolwater.h"
+#include "llmaniptranslate.h"
+#include "llface.h"
+#include "llfeaturemanager.h"
+#include "llfilepicker.h"
+#include "llfirstuse.h"
+#include "llfloater.h"
+#include "llfloaterbuildoptions.h"
+#include "llfloaterbuyland.h"
+#include "llfloatercamera.h"
+#include "llfloaterland.h"
+#include "llfloaterinspect.h"
+#include "llfloatermap.h"
+#include "llfloaternamedesc.h"
+#include "llfloaterpreference.h"
+#include "llfloatersnapshot.h"
+#include "llfloatertools.h"
+#include "llfloaterworldmap.h"
+#include "llfocusmgr.h"
+#include "llfontfreetype.h"
+#include "llgesturemgr.h"
+#include "llglheaders.h"
+#include "lltooltip.h"
+#include "llhudmanager.h"
+#include "llhudobject.h"
+#include "llhudview.h"
+#include "llimagebmp.h"
+#include "llimagej2c.h"
+#include "llimageworker.h"
+#include "llkeyboard.h"
+#include "lllineeditor.h"
+#include "llmenugl.h"
+#include "llmodaldialog.h"
+#include "llmorphview.h"
+#include "llmoveview.h"
+#include "llnavigationbar.h"
+#include "llpopupview.h"
+#include "llpreviewtexture.h"
+#include "llprogressview.h"
+#include "llresmgr.h"
+#include "llsidetray.h"
+#include "llselectmgr.h"
+#include "llrootview.h"
+#include "llrendersphere.h"
+#include "llstartup.h"
+#include "llstatusbar.h"
+#include "llstatview.h"
+#include "llsurface.h"
+#include "llsurfacepatch.h"
+#include "lltexlayer.h"
+#include "lltextbox.h"
+#include "lltexturecache.h"
+#include "lltexturefetch.h"
+#include "lltextureview.h"
+#include "lltool.h"
+#include "lltoolcomp.h"
+#include "lltooldraganddrop.h"
+#include "lltoolface.h"
+#include "lltoolfocus.h"
+#include "lltoolgrab.h"
+#include "lltoolmgr.h"
+#include "lltoolmorph.h"
+#include "lltoolpie.h"
+#include "lltoolselectland.h"
+#include "lltrans.h"
+#include "lluictrlfactory.h"
+#include "llurldispatcher.h" // SLURL from other app instance
+#include "llversioninfo.h"
+#include "llvieweraudio.h"
+#include "llviewercamera.h"
+#include "llviewergesture.h"
+#include "llviewertexturelist.h"
+#include "llviewerinventory.h"
+#include "llviewerkeyboard.h"
+#include "llviewermedia.h"
+#include "llviewermediafocus.h"
+#include "llviewermenu.h"
+#include "llviewermessage.h"
+#include "llviewerobjectlist.h"
+#include "llviewerparcelmgr.h"
+#include "llviewerregion.h"
+#include "llviewershadermgr.h"
+#include "llviewerstats.h"
+#include "llvoavatarself.h"
+#include "llvovolume.h"
+#include "llworld.h"
+#include "llworldmapview.h"
+#include "pipeline.h"
+#include "llappviewer.h"
+#include "llviewerdisplay.h"
+#include "llspatialpartition.h"
+#include "llviewerjoystick.h"
+#include "llviewernetwork.h"
+#include "llpostprocess.h"
+#include "llbottomtray.h"
+#include "llnearbychatbar.h"
+#include "llagentui.h"
+#include "llwearablelist.h"
+
+#include "llnotifications.h"
+#include "llnotificationsutil.h"
+#include "llnotificationmanager.h"
+
+#include "llfloaternotificationsconsole.h"
+
+#include "llnearbychat.h"
+#include "llviewerwindowlistener.h"
+#include "llpaneltopinfobar.h"
+
+#if LL_WINDOWS
+#include <tchar.h> // For Unicode conversion methods
+#endif
+
+//
+// Globals
+//
+void render_ui(F32 zoom_factor = 1.f, int subfield = 0);
+
+extern BOOL gDebugClicks;
+extern BOOL gDisplaySwapBuffers;
+extern BOOL gDepthDirty;
+extern BOOL gResizeScreenTexture;
+
+LLViewerWindow *gViewerWindow = NULL;
+
+LLFrameTimer gAwayTimer;
+LLFrameTimer gAwayTriggerTimer;
+
+BOOL gShowOverlayTitle = FALSE;
+
+LLViewerObject* gDebugRaycastObject = NULL;
+LLVector3 gDebugRaycastIntersection;
+LLVector2 gDebugRaycastTexCoord;
+LLVector3 gDebugRaycastNormal;
+LLVector3 gDebugRaycastBinormal;
+S32 gDebugRaycastFaceHit;
+
+// HUD display lines in lower right
+BOOL gDisplayWindInfo = FALSE;
+BOOL gDisplayCameraPos = FALSE;
+BOOL gDisplayFOV = FALSE;
+BOOL gDisplayBadge = FALSE;
+
+S32 CHAT_BAR_HEIGHT = 28;
+S32 OVERLAY_BAR_HEIGHT = 20;
+
+const U8 NO_FACE = 255;
+BOOL gQuietSnapshot = FALSE;
+
+const F32 MIN_AFK_TIME = 2.f; // minimum time after setting away state before coming back
+const F32 MAX_FAST_FRAME_TIME = 0.5f;
+const F32 FAST_FRAME_INCREMENT = 0.1f;
+
+const F32 MIN_DISPLAY_SCALE = 0.75f;
+
+std::string LLViewerWindow::sSnapshotBaseName;
+std::string LLViewerWindow::sSnapshotDir;
+
+std::string LLViewerWindow::sMovieBaseName;
+
+class RecordToChatConsole : public LLError::Recorder, public LLSingleton<RecordToChatConsole>
+{
+public:
+ virtual void recordMessage(LLError::ELevel level,
+ const std::string& message)
+ {
+ //FIXME: this is NOT thread safe, and will do bad things when a warning is issued from a non-UI thread
+
+ // only log warnings to chat console
+ //if (level == LLError::LEVEL_WARN)
+ //{
+ //LLFloaterChat* chat_floater = LLFloaterReg::findTypedInstance<LLFloaterChat>("chat");
+ //if (chat_floater && gSavedSettings.getBOOL("WarningsAsChat"))
+ //{
+ // LLChat chat;
+ // chat.mText = message;
+ // chat.mSourceType = CHAT_SOURCE_SYSTEM;
+
+ // chat_floater->addChat(chat, FALSE, FALSE);
+ //}
+ //}
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////
+//
+// LLDebugText
+//
+
+class LLDebugText
+{
+private:
+ struct Line
+ {
+ Line(const std::string& in_text, S32 in_x, S32 in_y) : text(in_text), x(in_x), y(in_y) {}
+ std::string text;
+ S32 x,y;
+ };
+
+ LLViewerWindow *mWindow;
+
+ typedef std::vector<Line> line_list_t;
+ line_list_t mLineList;
+ LLColor4 mTextColor;
+
+ void addText(S32 x, S32 y, const std::string &text)
+ {
+ mLineList.push_back(Line(text, x, y));
+ }
+
+ void clearText() { mLineList.clear(); }
+
+public:
+ LLDebugText(LLViewerWindow* window) : mWindow(window) {}
+
+ void update()
+ {
+ static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic") ;
+
+ std::string wind_vel_text;
+ std::string wind_vector_text;
+ std::string rwind_vel_text;
+ std::string rwind_vector_text;
+ std::string audio_text;
+
+ static const std::string beacon_particle = LLTrans::getString("BeaconParticle");
+ static const std::string beacon_physical = LLTrans::getString("BeaconPhysical");
+ static const std::string beacon_scripted = LLTrans::getString("BeaconScripted");
+ static const std::string beacon_scripted_touch = LLTrans::getString("BeaconScriptedTouch");
+ static const std::string beacon_sound = LLTrans::getString("BeaconSound");
+ static const std::string beacon_media = LLTrans::getString("BeaconMedia");
+ static const std::string particle_hiding = LLTrans::getString("ParticleHiding");
+
+ // Draw the statistics in a light gray
+ // and in a thin font
+ mTextColor = LLColor4( 0.86f, 0.86f, 0.86f, 1.f );
+
+ // Draw stuff growing up from right lower corner of screen
+ U32 xpos = mWindow->getWindowWidthScaled() - 350;
+ U32 ypos = 64;
+ const U32 y_inc = 20;
+
+ clearText();
+
+ if (gSavedSettings.getBOOL("DebugShowTime"))
+ {
+ const U32 y_inc2 = 15;
+ for (std::map<S32,LLFrameTimer>::reverse_iterator iter = gDebugTimers.rbegin();
+ iter != gDebugTimers.rend(); ++iter)
+ {
+ S32 idx = iter->first;
+ LLFrameTimer& timer = iter->second;
+ F32 time = timer.getElapsedTimeF32();
+ S32 hours = (S32)(time / (60*60));
+ S32 mins = (S32)((time - hours*(60*60)) / 60);
+ S32 secs = (S32)((time - hours*(60*60) - mins*60));
+ std::string label = gDebugTimerLabel[idx];
+ if (label.empty()) label = llformat("Debug: %d", idx);
+ addText(xpos, ypos, llformat(" %s: %d:%02d:%02d", label.c_str(), hours,mins,secs)); ypos += y_inc2;
+ }
+
+ F32 time = gFrameTimeSeconds;
+ S32 hours = (S32)(time / (60*60));
+ S32 mins = (S32)((time - hours*(60*60)) / 60);
+ S32 secs = (S32)((time - hours*(60*60) - mins*60));
+ addText(xpos, ypos, llformat("Time: %d:%02d:%02d", hours,mins,secs)); ypos += y_inc;
+ }
+
+#if LL_WINDOWS
+ if (gSavedSettings.getBOOL("DebugShowMemory"))
+ {
+ addText(xpos, ypos, llformat("Memory: %d (KB)", LLMemory::getWorkingSetSize() / 1024));
+ ypos += y_inc;
+ }
+#endif
+
+ if (gDisplayCameraPos)
+ {
+ std::string camera_view_text;
+ std::string camera_center_text;
+ std::string agent_view_text;
+ std::string agent_left_text;
+ std::string agent_center_text;
+ std::string agent_root_center_text;
+
+ LLVector3d tvector; // Temporary vector to hold data for printing.
+
+ // Update camera center, camera view, wind info every other frame
+ tvector = gAgent.getPositionGlobal();
+ agent_center_text = llformat("AgentCenter %f %f %f",
+ (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
+
+ if (isAgentAvatarValid())
+ {
+ tvector = gAgent.getPosGlobalFromAgent(gAgentAvatarp->mRoot.getWorldPosition());
+ agent_root_center_text = llformat("AgentRootCenter %f %f %f",
+ (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
+ }
+ else
+ {
+ agent_root_center_text = "---";
+ }
+
+
+ tvector = LLVector4(gAgent.getFrameAgent().getAtAxis());
+ agent_view_text = llformat("AgentAtAxis %f %f %f",
+ (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
+
+ tvector = LLVector4(gAgent.getFrameAgent().getLeftAxis());
+ agent_left_text = llformat("AgentLeftAxis %f %f %f",
+ (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
+
+ tvector = gAgentCamera.getCameraPositionGlobal();
+ camera_center_text = llformat("CameraCenter %f %f %f",
+ (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
+
+ tvector = LLVector4(LLViewerCamera::getInstance()->getAtAxis());
+ camera_view_text = llformat("CameraAtAxis %f %f %f",
+ (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
+
+ addText(xpos, ypos, agent_center_text); ypos += y_inc;
+ addText(xpos, ypos, agent_root_center_text); ypos += y_inc;
+ addText(xpos, ypos, agent_view_text); ypos += y_inc;
+ addText(xpos, ypos, agent_left_text); ypos += y_inc;
+ addText(xpos, ypos, camera_center_text); ypos += y_inc;
+ addText(xpos, ypos, camera_view_text); ypos += y_inc;
+ }
+
+ if (gDisplayWindInfo)
+ {
+ wind_vel_text = llformat("Wind velocity %.2f m/s", gWindVec.magVec());
+ wind_vector_text = llformat("Wind vector %.2f %.2f %.2f", gWindVec.mV[0], gWindVec.mV[1], gWindVec.mV[2]);
+ rwind_vel_text = llformat("RWind vel %.2f m/s", gRelativeWindVec.magVec());
+ rwind_vector_text = llformat("RWind vec %.2f %.2f %.2f", gRelativeWindVec.mV[0], gRelativeWindVec.mV[1], gRelativeWindVec.mV[2]);
+
+ addText(xpos, ypos, wind_vel_text); ypos += y_inc;
+ addText(xpos, ypos, wind_vector_text); ypos += y_inc;
+ addText(xpos, ypos, rwind_vel_text); ypos += y_inc;
+ addText(xpos, ypos, rwind_vector_text); ypos += y_inc;
+ }
+ if (gDisplayWindInfo)
+ {
+ if (gAudiop)
+ {
+ audio_text= llformat("Audio for wind: %d", gAudiop->isWindEnabled());
+ }
+ addText(xpos, ypos, audio_text); ypos += y_inc;
+ }
+ if (gDisplayFOV)
+ {
+ addText(xpos, ypos, llformat("FOV: %2.1f deg", RAD_TO_DEG * LLViewerCamera::getInstance()->getView()));
+ ypos += y_inc;
+ }
+ if (gDisplayBadge)
+ {
+ addText(xpos, ypos+(y_inc/2), llformat("Hippos!", RAD_TO_DEG * LLViewerCamera::getInstance()->getView()));
+ ypos += y_inc * 2;
+ }
+
+ /*if (LLViewerJoystick::getInstance()->getOverrideCamera())
+ {
+ addText(xpos + 200, ypos, llformat("Flycam"));
+ ypos += y_inc;
+ }*/
+
+ if (gSavedSettings.getBOOL("DebugShowRenderInfo"))
+ {
+ if (gPipeline.getUseVertexShaders() == 0)
+ {
+ addText(xpos, ypos, "Shaders Disabled");
+ ypos += y_inc;
+ }
+ addText(xpos, ypos, llformat("%d MB Vertex Data", LLVertexBuffer::sAllocatedBytes/(1024*1024)));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d Vertex Buffers", LLVertexBuffer::sGLCount));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d Mapped Buffers", LLVertexBuffer::sMappedCount));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d Vertex Buffer Binds", LLVertexBuffer::sBindCount));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d Vertex Buffer Sets", LLVertexBuffer::sSetCount));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d Texture Binds", LLImageGL::sBindCount));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d Unique Textures", LLImageGL::sUniqueCount));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d Render Calls", gPipeline.mBatchCount));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d Matrix Ops", gPipeline.mMatrixOpCount));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d Texture Matrix Ops", gPipeline.mTextureMatrixOps));
+ ypos += y_inc;
+
+ gPipeline.mTextureMatrixOps = 0;
+ gPipeline.mMatrixOpCount = 0;
+
+ if (gPipeline.mBatchCount > 0)
+ {
+ addText(xpos, ypos, llformat("Batch min/max/mean: %d/%d/%d", gPipeline.mMinBatchSize, gPipeline.mMaxBatchSize,
+ gPipeline.mTrianglesDrawn/gPipeline.mBatchCount));
+
+ gPipeline.mMinBatchSize = gPipeline.mMaxBatchSize;
+ gPipeline.mMaxBatchSize = 0;
+ gPipeline.mBatchCount = 0;
+ }
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("UI Verts/Calls: %d/%d", LLRender::sUIVerts, LLRender::sUICalls));
+ LLRender::sUICalls = LLRender::sUIVerts = 0;
+ ypos += y_inc;
+
+ addText(xpos,ypos, llformat("%d/%d Nodes visible", gPipeline.mNumVisibleNodes, LLSpatialGroup::sNodeCount));
+
+ ypos += y_inc;
+
+
+ addText(xpos,ypos, llformat("%d Avatars visible", LLVOAvatar::sNumVisibleAvatars));
+
+ ypos += y_inc;
+
+ addText(xpos,ypos, llformat("%d Lights visible", LLPipeline::sVisibleLightCount));
+
+ ypos += y_inc;
+
+ LLVertexBuffer::sBindCount = LLImageGL::sBindCount =
+ LLVertexBuffer::sSetCount = LLImageGL::sUniqueCount =
+ gPipeline.mNumVisibleNodes = LLPipeline::sVisibleLightCount = 0;
+ }
+ if (gSavedSettings.getBOOL("DebugShowRenderMatrices"))
+ {
+ addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[12], gGLProjection[13], gGLProjection[14], gGLProjection[15]));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[8], gGLProjection[9], gGLProjection[10], gGLProjection[11]));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[4], gGLProjection[5], gGLProjection[6], gGLProjection[7]));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[0], gGLProjection[1], gGLProjection[2], gGLProjection[3]));
+ ypos += y_inc;
+
+ addText(xpos, ypos, "Projection Matrix");
+ ypos += y_inc;
+
+
+ addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[12], gGLModelView[13], gGLModelView[14], gGLModelView[15]));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[8], gGLModelView[9], gGLModelView[10], gGLModelView[11]));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[4], gGLModelView[5], gGLModelView[6], gGLModelView[7]));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[0], gGLModelView[1], gGLModelView[2], gGLModelView[3]));
+ ypos += y_inc;
+
+ addText(xpos, ypos, "View Matrix");
+ ypos += y_inc;
+ }
+ if (gSavedSettings.getBOOL("DebugShowColor"))
+ {
+ U8 color[4];
+ LLCoordGL coord = gViewerWindow->getCurrentMouse();
+ glReadPixels(coord.mX, coord.mY, 1,1,GL_RGBA, GL_UNSIGNED_BYTE, color);
+ addText(xpos, ypos, llformat("%d %d %d %d", color[0], color[1], color[2], color[3]));
+ ypos += y_inc;
+ }
+ // only display these messages if we are actually rendering beacons at this moment
+ if (LLPipeline::getRenderBeacons(NULL) && LLFloaterReg::instanceVisible("beacons"))
+ {
+ if (LLPipeline::getRenderParticleBeacons(NULL))
+ {
+ addText(xpos, ypos, beacon_particle);
+ ypos += y_inc;
+ }
+ if (LLPipeline::toggleRenderTypeControlNegated((void*)LLPipeline::RENDER_TYPE_PARTICLES))
+ {
+ addText(xpos, ypos, particle_hiding);
+ ypos += y_inc;
+ }
+ if (LLPipeline::getRenderPhysicalBeacons(NULL))
+ {
+ addText(xpos, ypos, beacon_physical);
+ ypos += y_inc;
+ }
+ if (LLPipeline::getRenderScriptedBeacons(NULL))
+ {
+ addText(xpos, ypos, beacon_scripted);
+ ypos += y_inc;
+ }
+ else
+ if (LLPipeline::getRenderScriptedTouchBeacons(NULL))
+ {
+ addText(xpos, ypos, beacon_scripted_touch);
+ ypos += y_inc;
+ }
+ if (LLPipeline::getRenderSoundBeacons(NULL))
+ {
+ addText(xpos, ypos, beacon_sound);
+ ypos += y_inc;
+ }
+ }
+ if(log_texture_traffic)
+ {
+ U32 old_y = ypos ;
+ for(S32 i = LLViewerTexture::BOOST_NONE; i < LLViewerTexture::MAX_GL_IMAGE_CATEGORY; i++)
+ {
+ if(gTotalTextureBytesPerBoostLevel[i] > 0)
+ {
+ addText(xpos, ypos, llformat("Boost_Level %d: %.3f MB", i, (F32)gTotalTextureBytesPerBoostLevel[i] / (1024 * 1024)));
+ ypos += y_inc;
+ }
+ }
+ if(ypos != old_y)
+ {
+ addText(xpos, ypos, "Network traffic for textures:");
+ ypos += y_inc;
+ }
+ }
+
+ if (gSavedSettings.getBOOL("DebugShowTextureInfo"))
+ {
+ LLViewerObject* objectp = NULL ;
+ //objectp = = gAgentCamera.getFocusObject();
+
+ LLSelectNode* nodep = LLSelectMgr::instance().getHoverNode();
+ if (nodep)
+ {
+ objectp = nodep->getObject();
+ }
+ if (objectp && !objectp->isDead())
+ {
+ S32 num_faces = objectp->mDrawable->getNumFaces() ;
+
+ for(S32 i = 0 ; i < num_faces; i++)
+ {
+ LLFace* facep = objectp->mDrawable->getFace(i) ;
+ if(facep)
+ {
+ //addText(xpos, ypos, llformat("ts_min: %.3f ts_max: %.3f tt_min: %.3f tt_max: %.3f", facep->mTexExtents[0].mV[0], facep->mTexExtents[1].mV[0],
+ // facep->mTexExtents[0].mV[1], facep->mTexExtents[1].mV[1]));
+ //ypos += y_inc;
+
+ addText(xpos, ypos, llformat("v_size: %.3f: p_size: %.3f", facep->getVirtualSize(), facep->getPixelArea()));
+ ypos += y_inc;
+
+ //const LLTextureEntry *tep = facep->getTextureEntry();
+ //if(tep)
+ //{
+ // addText(xpos, ypos, llformat("scale_s: %.3f: scale_t: %.3f", tep->mScaleS, tep->mScaleT)) ;
+ // ypos += y_inc;
+ //}
+
+ LLViewerTexture* tex = facep->getTexture() ;
+ if(tex)
+ {
+ addText(xpos, ypos, llformat("ID: %s v_size: %.3f", tex->getID().asString().c_str(), tex->getMaxVirtualSize()));
+ ypos += y_inc;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ void draw()
+ {
+ for (line_list_t::iterator iter = mLineList.begin();
+ iter != mLineList.end(); ++iter)
+ {
+ const Line& line = *iter;
+ LLFontGL::getFontMonospace()->renderUTF8(line.text, 0, (F32)line.x, (F32)line.y, mTextColor,
+ LLFontGL::LEFT, LLFontGL::TOP,
+ LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
+ }
+ mLineList.clear();
+ }
+
+};
+
+void LLViewerWindow::updateDebugText()
+{
+ mDebugText->update();
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// LLViewerWindow
+//
+
+BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down)
+{
+ const char* buttonname = "";
+ const char* buttonstatestr = "";
+ S32 x = pos.mX;
+ S32 y = pos.mY;
+ x = llround((F32)x / mDisplayScale.mV[VX]);
+ y = llround((F32)y / mDisplayScale.mV[VY]);
+
+ // only send mouse clicks to UI if UI is visible
+ if(gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+
+ if (down)
+ {
+ buttonstatestr = "down" ;
+ }
+ else
+ {
+ buttonstatestr = "up" ;
+ }
+
+ switch (clicktype)
+ {
+ case LLMouseHandler::CLICK_LEFT:
+ mLeftMouseDown = down;
+ buttonname = "Left";
+ break;
+ case LLMouseHandler::CLICK_RIGHT:
+ mRightMouseDown = down;
+ buttonname = "Right";
+ break;
+ case LLMouseHandler::CLICK_MIDDLE:
+ mMiddleMouseDown = down;
+ buttonname = "Middle";
+ break;
+ case LLMouseHandler::CLICK_DOUBLELEFT:
+ mLeftMouseDown = down;
+ buttonname = "Left Double Click";
+ break;
+ }
+
+ LLView::sMouseHandlerMessage.clear();
+
+ if (gMenuBarView)
+ {
+ // stop ALT-key access to menu
+ gMenuBarView->resetMenuTrigger();
+ }
+
+ if (gDebugClicks)
+ {
+ llinfos << "ViewerWindow " << buttonname << " mouse " << buttonstatestr << " at " << x << "," << y << llendl;
+ }
+
+ // Make sure we get a corresponding mouseup event, even if the mouse leaves the window
+ if (down)
+ mWindow->captureMouse();
+ else
+ mWindow->releaseMouse();
+
+ // Indicate mouse was active
+ LLUI::resetMouseIdleTimer();
+
+ // Don't let the user move the mouse out of the window until mouse up.
+ if( LLToolMgr::getInstance()->getCurrentTool()->clipMouseWhenDown() )
+ {
+ mWindow->setMouseClipping(down);
+ }
+
+ LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
+ if( mouse_captor )
+ {
+ S32 local_x;
+ S32 local_y;
+ mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
+ if (LLView::sDebugMouseHandling)
+ {
+ llinfos << buttonname << " Mouse " << buttonstatestr << " handled by captor " << mouse_captor->getName() << llendl;
+ }
+ return mouse_captor->handleAnyMouseClick(local_x, local_y, mask, clicktype, down);
+ }
+
+ // Topmost view gets a chance before the hierarchy
+ //LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
+ //if (top_ctrl)
+ //{
+ // S32 local_x, local_y;
+ // top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
+ // if (top_ctrl->pointInView(local_x, local_y))
+ // {
+ // return top_ctrl->handleAnyMouseClick(local_x, local_y, mask, clicktype, down) ;
+ // }
+ // else
+ // {
+ // if (down)
+ // {
+ // gFocusMgr.setTopCtrl(NULL);
+ // }
+ // }
+ //}
+
+ // Give the UI views a chance to process the click
+ if( mRootView->handleAnyMouseClick(x, y, mask, clicktype, down) )
+ {
+ if (LLView::sDebugMouseHandling)
+ {
+ llinfos << buttonname << " Mouse " << buttonstatestr << " " << LLView::sMouseHandlerMessage << llendl;
+ }
+ return TRUE;
+ }
+ else if (LLView::sDebugMouseHandling)
+ {
+ llinfos << buttonname << " Mouse " << buttonstatestr << " not handled by view" << llendl;
+ }
+ }
+
+ // Do not allow tool manager to handle mouseclicks if we have disconnected
+ if(!gDisconnected && LLToolMgr::getInstance()->getCurrentTool()->handleAnyMouseClick( x, y, mask, clicktype, down ) )
+ {
+ return TRUE;
+ }
+
+
+ // If we got this far on a down-click, it wasn't handled.
+ // Up-clicks, though, are always handled as far as the OS is concerned.
+ BOOL default_rtn = !down;
+ return default_rtn;
+}
+
+BOOL LLViewerWindow::handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ BOOL down = TRUE;
+ return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down);
+}
+
+BOOL LLViewerWindow::handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ // try handling as a double-click first, then a single-click if that
+ // wasn't handled.
+ BOOL down = TRUE;
+ if (handleAnyMouseClick(window, pos, mask,
+ LLMouseHandler::CLICK_DOUBLELEFT, down))
+ {
+ return TRUE;
+ }
+ return handleMouseDown(window, pos, mask);
+}
+
+BOOL LLViewerWindow::handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ BOOL down = FALSE;
+ return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down);
+}
+
+
+BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ S32 x = pos.mX;
+ S32 y = pos.mY;
+ x = llround((F32)x / mDisplayScale.mV[VX]);
+ y = llround((F32)y / mDisplayScale.mV[VY]);
+
+ BOOL down = TRUE;
+ BOOL handle = handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down);
+ if (handle)
+ return handle;
+
+ // *HACK: this should be rolled into the composite tool logic, not
+ // hardcoded at the top level.
+ if (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance())
+ {
+ // If the current tool didn't process the click, we should show
+ // the pie menu. This can be done by passing the event to the pie
+ // menu tool.
+ LLToolPie::getInstance()->handleRightMouseDown(x, y, mask);
+ // show_context_menu( x, y, mask );
+ }
+
+ return TRUE;
+}
+
+BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ BOOL down = FALSE;
+ return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down);
+}
+
+BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ BOOL down = TRUE;
+ LLVoiceClient::getInstance()->middleMouseState(true);
+ handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down);
+
+ // Always handled as far as the OS is concerned.
+ return TRUE;
+}
+
+LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *window, LLCoordGL pos, MASK mask, LLWindowCallbacks::DragNDropAction action, std::string data)
+{
+ LLWindowCallbacks::DragNDropResult result = LLWindowCallbacks::DND_NONE;
+
+ const bool prim_media_dnd_enabled = gSavedSettings.getBOOL("PrimMediaDragNDrop");
+ const bool slurl_dnd_enabled = gSavedSettings.getBOOL("SLURLDragNDrop");
+
+ if ( prim_media_dnd_enabled || slurl_dnd_enabled )
+ {
+ switch(action)
+ {
+ // Much of the handling for these two cases is the same.
+ case LLWindowCallbacks::DNDA_TRACK:
+ case LLWindowCallbacks::DNDA_DROPPED:
+ case LLWindowCallbacks::DNDA_START_TRACKING:
+ {
+ bool drop = (LLWindowCallbacks::DNDA_DROPPED == action);
+
+ if (slurl_dnd_enabled)
+ {
+ LLSLURL dropped_slurl(data);
+ if(dropped_slurl.isSpatial())
+ {
+ if (drop)
+ {
+ LLURLDispatcher::dispatch( dropped_slurl.getSLURLString(), NULL, true );
+ return LLWindowCallbacks::DND_MOVE;
+ }
+ return LLWindowCallbacks::DND_COPY;
+ }
+ }
+
+ if (prim_media_dnd_enabled)
+ {
+ LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY, TRUE /*BOOL pick_transparent*/ );
+
+ LLUUID object_id = pick_info.getObjectID();
+ S32 object_face = pick_info.mObjectFace;
+ std::string url = data;
+
+ lldebugs << "Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << llendl;
+
+ LLVOVolume *obj = dynamic_cast<LLVOVolume*>(static_cast<LLViewerObject*>(pick_info.getObject()));
+
+ if (obj && !obj->getRegion()->getCapability("ObjectMedia").empty())
+ {
+ LLTextureEntry *te = obj->getTE(object_face);
+
+ // can modify URL if we can modify the object or we have navigate permissions
+ bool allow_modify_url = obj->permModify() || obj->hasMediaPermission( te->getMediaData(), LLVOVolume::MEDIA_PERM_INTERACT );
+
+ if (te && allow_modify_url )
+ {
+ if (drop)
+ {
+ // object does NOT have media already
+ if ( ! te->hasMedia() )
+ {
+ // we are allowed to modify the object
+ if ( obj->permModify() )
+ {
+ // Create new media entry
+ LLSD media_data;
+ // XXX Should we really do Home URL too?
+ media_data[LLMediaEntry::HOME_URL_KEY] = url;
+ media_data[LLMediaEntry::CURRENT_URL_KEY] = url;
+ media_data[LLMediaEntry::AUTO_PLAY_KEY] = true;
+ obj->syncMediaData(object_face, media_data, true, true);
+ // XXX This shouldn't be necessary, should it ?!?
+ if (obj->getMediaImpl(object_face))
+ obj->getMediaImpl(object_face)->navigateReload();
+ obj->sendMediaDataUpdate();
+
+ result = LLWindowCallbacks::DND_COPY;
+ }
+ }
+ else
+ // object HAS media already
+ {
+ // URL passes the whitelist
+ if (te->getMediaData()->checkCandidateUrl( url ) )
+ {
+ // just navigate to the URL
+ if (obj->getMediaImpl(object_face))
+ {
+ obj->getMediaImpl(object_face)->navigateTo(url);
+ }
+ else
+ {
+ // This is very strange. Navigation should
+ // happen via the Impl, but we don't have one.
+ // This sends it to the server, which /should/
+ // trigger us getting it. Hopefully.
+ LLSD media_data;
+ media_data[LLMediaEntry::CURRENT_URL_KEY] = url;
+ obj->syncMediaData(object_face, media_data, true, true);
+ obj->sendMediaDataUpdate();
+ }
+ result = LLWindowCallbacks::DND_LINK;
+
+ }
+ }
+ LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject);
+ mDragHoveredObject = NULL;
+
+ }
+ else
+ {
+ // Check the whitelist, if there's media (otherwise just show it)
+ if (te->getMediaData() == NULL || te->getMediaData()->checkCandidateUrl(url))
+ {
+ if ( obj != mDragHoveredObject)
+ {
+ // Highlight the dragged object
+ LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject);
+ mDragHoveredObject = obj;
+ LLSelectMgr::getInstance()->highlightObjectOnly(mDragHoveredObject);
+ }
+ result = (! te->hasMedia()) ? LLWindowCallbacks::DND_COPY : LLWindowCallbacks::DND_LINK;
+
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case LLWindowCallbacks::DNDA_STOP_TRACKING:
+ // The cleanup case below will make sure things are unhilighted if necessary.
+ break;
+ }
+
+ if (prim_media_dnd_enabled &&
+ result == LLWindowCallbacks::DND_NONE && !mDragHoveredObject.isNull())
+ {
+ LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject);
+ mDragHoveredObject = NULL;
+ }
+ }
+
+ return result;
+}
+
+BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ BOOL down = FALSE;
+ LLVoiceClient::getInstance()->middleMouseState(false);
+ handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down);
+
+ // Always handled as far as the OS is concerned.
+ return TRUE;
+}
+
+// WARNING: this is potentially called multiple times per frame
+void LLViewerWindow::handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ S32 x = pos.mX;
+ S32 y = pos.mY;
+
+ x = llround((F32)x / mDisplayScale.mV[VX]);
+ y = llround((F32)y / mDisplayScale.mV[VY]);
+
+ mMouseInWindow = TRUE;
+
+ // Save mouse point for access during idle() and display()
+
+ LLCoordGL mouse_point(x, y);
+
+ if (mouse_point != mCurrentMousePoint)
+ {
+ LLUI::resetMouseIdleTimer();
+ }
+
+ saveLastMouse(mouse_point);
+
+ mWindow->showCursorFromMouseMove();
+
+ if (gAwayTimer.getElapsedTimeF32() > MIN_AFK_TIME)
+ {
+ gAgent.clearAFK();
+ }
+}
+
+void LLViewerWindow::handleMouseLeave(LLWindow *window)
+{
+ // Note: we won't get this if we have captured the mouse.
+ llassert( gFocusMgr.getMouseCapture() == NULL );
+ mMouseInWindow = FALSE;
+ LLToolTipMgr::instance().blockToolTips();
+}
+
+BOOL LLViewerWindow::handleCloseRequest(LLWindow *window)
+{
+ // User has indicated they want to close, but we may need to ask
+ // about modified documents.
+ LLAppViewer::instance()->userQuit();
+ // Don't quit immediately
+ return FALSE;
+}
+
+void LLViewerWindow::handleQuit(LLWindow *window)
+{
+ LLAppViewer::instance()->forceQuit();
+}
+
+void LLViewerWindow::handleResize(LLWindow *window, S32 width, S32 height)
+{
+ reshape(width, height);
+ mResDirty = true;
+}
+
+// The top-level window has gained focus (e.g. via ALT-TAB)
+void LLViewerWindow::handleFocus(LLWindow *window)
+{
+ gFocusMgr.setAppHasFocus(TRUE);
+ LLModalDialog::onAppFocusGained();
+
+ gAgent.onAppFocusGained();
+ LLToolMgr::getInstance()->onAppFocusGained();
+
+ // See if we're coming in with modifier keys held down
+ if (gKeyboard)
+ {
+ gKeyboard->resetMaskKeys();
+ }
+
+ // resume foreground running timer
+ // since we artifically limit framerate when not frontmost
+ gForegroundTime.unpause();
+}
+
+// The top-level window has lost focus (e.g. via ALT-TAB)
+void LLViewerWindow::handleFocusLost(LLWindow *window)
+{
+ gFocusMgr.setAppHasFocus(FALSE);
+ //LLModalDialog::onAppFocusLost();
+ LLToolMgr::getInstance()->onAppFocusLost();
+ gFocusMgr.setMouseCapture( NULL );
+
+ if (gMenuBarView)
+ {
+ // stop ALT-key access to menu
+ gMenuBarView->resetMenuTrigger();
+ }
+
+ // restore mouse cursor
+ showCursor();
+ getWindow()->setMouseClipping(FALSE);
+
+ // If losing focus while keys are down, reset them.
+ if (gKeyboard)
+ {
+ gKeyboard->resetKeys();
+ }
+
+ // pause timer that tracks total foreground running time
+ gForegroundTime.pause();
+}
+
+
+BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated)
+{
+ // Let the voice chat code check for its PTT key. Note that this never affects event processing.
+ LLVoiceClient::getInstance()->keyDown(key, mask);
+
+ if (gAwayTimer.getElapsedTimeF32() > MIN_AFK_TIME)
+ {
+ gAgent.clearAFK();
+ }
+
+ // *NOTE: We want to interpret KEY_RETURN later when it arrives as
+ // a Unicode char, not as a keydown. Otherwise when client frame
+ // rate is really low, hitting return sends your chat text before
+ // it's all entered/processed.
+ if (key == KEY_RETURN && mask == MASK_NONE)
+ {
+ return FALSE;
+ }
+
+ return gViewerKeyboard.handleKey(key, mask, repeated);
+}
+
+BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key, MASK mask)
+{
+ // Let the voice chat code check for its PTT key. Note that this never affects event processing.
+ LLVoiceClient::getInstance()->keyUp(key, mask);
+
+ return FALSE;
+}
+
+
+void LLViewerWindow::handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
+{
+ LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true);
+ return gViewerKeyboard.scanKey(key, key_down, key_up, key_level);
+}
+
+
+
+
+BOOL LLViewerWindow::handleActivate(LLWindow *window, BOOL activated)
+{
+ if (activated)
+ {
+ mActive = TRUE;
+ send_agent_resume();
+ gAgent.clearAFK();
+
+ // Unmute audio
+ audio_update_volume();
+ }
+ else
+ {
+ mActive = FALSE;
+
+ if (gSavedSettings.getS32("AFKTimeout"))
+ {
+ gAgent.setAFK();
+ }
+
+ // SL-53351: Make sure we're not in mouselook when minimised, to prevent control issues
+ if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK)
+ {
+ gAgentCamera.changeCameraToDefault();
+ }
+
+ send_agent_pause();
+
+ // Mute audio
+ audio_update_volume();
+ }
+ return TRUE;
+}
+
+BOOL LLViewerWindow::handleActivateApp(LLWindow *window, BOOL activating)
+{
+ //if (!activating) gAgentCamera.changeCameraToDefault();
+
+ LLViewerJoystick::getInstance()->setNeedsReset(true);
+ return FALSE;
+}
+
+
+void LLViewerWindow::handleMenuSelect(LLWindow *window, S32 menu_item)
+{
+}
+
+
+BOOL LLViewerWindow::handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S32 height)
+{
+#if LL_WINDOWS
+ if (gNoRender)
+ {
+ HWND window_handle = (HWND)window->getPlatformWindow();
+ PAINTSTRUCT ps;
+ HDC hdc;
+
+ RECT wnd_rect;
+ wnd_rect.left = 0;
+ wnd_rect.top = 0;
+ wnd_rect.bottom = 200;
+ wnd_rect.right = 500;
+
+ hdc = BeginPaint(window_handle, &ps);
+ //SetBKColor(hdc, RGB(255, 255, 255));
+ FillRect(hdc, &wnd_rect, CreateSolidBrush(RGB(255, 255, 255)));
+
+ std::string temp_str;
+ temp_str = llformat( "FPS %3.1f Phy FPS %2.1f Time Dil %1.3f", /* Flawfinder: ignore */
+ LLViewerStats::getInstance()->mFPSStat.getMeanPerSec(),
+ LLViewerStats::getInstance()->mSimPhysicsFPS.getPrev(0),
+ LLViewerStats::getInstance()->mSimTimeDilation.getPrev(0));
+ S32 len = temp_str.length();
+ TextOutA(hdc, 0, 0, temp_str.c_str(), len);
+
+
+ LLVector3d pos_global = gAgent.getPositionGlobal();
+ temp_str = llformat( "Avatar pos %6.1lf %6.1lf %6.1lf", pos_global.mdV[0], pos_global.mdV[1], pos_global.mdV[2]);
+ len = temp_str.length();
+ TextOutA(hdc, 0, 25, temp_str.c_str(), len);
+
+ TextOutA(hdc, 0, 50, "Set \"DisableRendering FALSE\" in settings.ini file to reenable", 61);
+ EndPaint(window_handle, &ps);
+ return TRUE;
+ }
+#endif
+ return FALSE;
+}
+
+
+void LLViewerWindow::handleScrollWheel(LLWindow *window, S32 clicks)
+{
+ handleScrollWheel( clicks );
+}
+
+void LLViewerWindow::handleWindowBlock(LLWindow *window)
+{
+ send_agent_pause();
+}
+
+void LLViewerWindow::handleWindowUnblock(LLWindow *window)
+{
+ send_agent_resume();
+}
+
+void LLViewerWindow::handleDataCopy(LLWindow *window, S32 data_type, void *data)
+{
+ const S32 SLURL_MESSAGE_TYPE = 0;
+ switch (data_type)
+ {
+ case SLURL_MESSAGE_TYPE:
+ // received URL
+ std::string url = (const char*)data;
+ LLMediaCtrl* web = NULL;
+ const bool trusted_browser = false;
+ if (LLURLDispatcher::dispatch(url, web, trusted_browser))
+ {
+ // bring window to foreground, as it has just been "launched" from a URL
+ mWindow->bringToFront();
+ }
+ break;
+ }
+}
+
+BOOL LLViewerWindow::handleTimerEvent(LLWindow *window)
+{
+ if (LLViewerJoystick::getInstance()->getOverrideCamera())
+ {
+ LLViewerJoystick::getInstance()->updateStatus();
+ return TRUE;
+ }
+ return FALSE;
+}
+
+BOOL LLViewerWindow::handleDeviceChange(LLWindow *window)
+{
+ // give a chance to use a joystick after startup (hot-plugging)
+ if (!LLViewerJoystick::getInstance()->isJoystickInitialized() )
+ {
+ LLViewerJoystick::getInstance()->init(true);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void LLViewerWindow::handlePingWatchdog(LLWindow *window, const char * msg)
+{
+ LLAppViewer::instance()->pingMainloopTimeout(msg);
+}
+
+
+void LLViewerWindow::handleResumeWatchdog(LLWindow *window)
+{
+ LLAppViewer::instance()->resumeMainloopTimeout();
+}
+
+void LLViewerWindow::handlePauseWatchdog(LLWindow *window)
+{
+ LLAppViewer::instance()->pauseMainloopTimeout();
+}
+
+//virtual
+std::string LLViewerWindow::translateString(const char* tag)
+{
+ return LLTrans::getString( std::string(tag) );
+}
+
+//virtual
+std::string LLViewerWindow::translateString(const char* tag,
+ const std::map<std::string, std::string>& args)
+{
+ // LLTrans uses a special subclass of std::string for format maps,
+ // but we must use std::map<> in these callbacks, otherwise we create
+ // a dependency between LLWindow and LLFormatMapString. So copy the data.
+ LLStringUtil::format_map_t args_copy;
+ std::map<std::string,std::string>::const_iterator it = args.begin();
+ for ( ; it != args.end(); ++it)
+ {
+ args_copy[it->first] = it->second;
+ }
+ return LLTrans::getString( std::string(tag), args_copy);
+}
+
+//
+// Classes
+//
+LLViewerWindow::LLViewerWindow(
+ const std::string& title, const std::string& name,
+ S32 x, S32 y,
+ S32 width, S32 height,
+ BOOL fullscreen, BOOL ignore_pixel_depth) // fullscreen is no longer used
+ :
+ mWindow(NULL),
+ mActive(TRUE),
+ mWindowRectRaw(0, height, width, 0),
+ mWindowRectScaled(0, height, width, 0),
+ mWorldViewRectRaw(0, height, width, 0),
+ mLeftMouseDown(FALSE),
+ mMiddleMouseDown(FALSE),
+ mRightMouseDown(FALSE),
+ mMouseInWindow( FALSE ),
+ mLastMask( MASK_NONE ),
+ mToolStored( NULL ),
+ mHideCursorPermanent( FALSE ),
+ mCursorHidden(FALSE),
+ mIgnoreActivate( FALSE ),
+ mResDirty(false),
+ mStatesDirty(false),
+ mCurrResolutionIndex(0),
+ mViewerWindowListener(new LLViewerWindowListener(this)),
+ mProgressView(NULL)
+{
+ LLNotificationChannel::buildChannel("VW_alerts", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "alert"));
+ LLNotificationChannel::buildChannel("VW_alertmodal", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "alertmodal"));
+
+ LLNotifications::instance().getChannel("VW_alerts")->connectChanged(&LLViewerWindow::onAlert);
+ LLNotifications::instance().getChannel("VW_alertmodal")->connectChanged(&LLViewerWindow::onAlert);
+ LLNotifications::instance().setIgnoreAllNotifications(gSavedSettings.getBOOL("IgnoreAllNotifications"));
+ llinfos << "NOTE: ALL NOTIFICATIONS THAT OCCUR WILL GET ADDED TO IGNORE LIST FOR LATER RUNS." << llendl;
+
+ // Default to application directory.
+ LLViewerWindow::sSnapshotBaseName = "Snapshot";
+ LLViewerWindow::sMovieBaseName = "SLmovie";
+ resetSnapshotLoc();
+
+ // create window
+ mWindow = LLWindowManager::createWindow(this,
+ title, name, x, y, width, height, 0,
+ fullscreen,
+ gNoRender,
+ gSavedSettings.getBOOL("DisableVerticalSync"),
+ !gNoRender,
+ ignore_pixel_depth,
+ gSavedSettings.getBOOL("RenderUseFBO") ? 0 : gSavedSettings.getU32("RenderFSAASamples")); //don't use window level anti-aliasing if FBOs are enabled
+
+ if (!LLAppViewer::instance()->restoreErrorTrap())
+ {
+ LL_WARNS("Window") << " Someone took over my signal/exception handler (post createWindow)!" << LL_ENDL;
+ }
+
+ LLCoordScreen scr;
+ mWindow->getSize(&scr);
+
+ if(fullscreen && ( scr.mX!=width || scr.mY!=height))
+ {
+ llwarns << "Fullscreen has forced us in to a different resolution now using "<<scr.mX<<" x "<<scr.mY<<llendl;
+ gSavedSettings.setS32("FullScreenWidth",scr.mX);
+ gSavedSettings.setS32("FullScreenHeight",scr.mY);
+ }
+
+ if (NULL == mWindow)
+ {
+ LLSplashScreen::update(LLTrans::getString("ShuttingDown"));
+#if LL_LINUX || LL_SOLARIS
+ llwarns << "Unable to create window, be sure screen is set at 32-bit color and your graphics driver is configured correctly. See README-linux.txt or README-solaris.txt for further information."
+ << llendl;
+#else
+ LL_WARNS("Window") << "Unable to create window, be sure screen is set at 32-bit color in Control Panels->Display->Settings"
+ << LL_ENDL;
+#endif
+ LLAppViewer::instance()->fastQuit(1);
+ }
+
+ // Get the real window rect the window was created with (since there are various OS-dependent reasons why
+ // the size of a window or fullscreen context may have been adjusted slightly...)
+ F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor");
+
+ mDisplayScale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f));
+ mDisplayScale *= ui_scale_factor;
+ LLUI::setScaleFactor(mDisplayScale);
+
+ {
+ LLCoordWindow size;
+ mWindow->getSize(&size);
+ mWindowRectRaw.set(0, size.mY, size.mX, 0);
+ mWindowRectScaled.set(0, llround((F32)size.mY / mDisplayScale.mV[VY]), llround((F32)size.mX / mDisplayScale.mV[VX]), 0);
+ }
+
+ LLFontManager::initClass();
+
+ //
+ // We want to set this stuff up BEFORE we initialize the pipeline, so we can turn off
+ // stuff like AGP if we think that it'll crash the viewer.
+ //
+ LL_DEBUGS("Window") << "Loading feature tables." << LL_ENDL;
+
+ LLFeatureManager::getInstance()->init();
+
+ // Initialize OpenGL Renderer
+ if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderVBOEnable") ||
+ !gGLManager.mHasVertexBufferObject)
+ {
+ gSavedSettings.setBOOL("RenderVBOEnable", FALSE);
+ }
+ LLVertexBuffer::initClass(gSavedSettings.getBOOL("RenderVBOEnable"), gSavedSettings.getBOOL("RenderVBOMappingDisable"));
+
+ if (LLFeatureManager::getInstance()->isSafe()
+ || (gSavedSettings.getS32("LastFeatureVersion") != LLFeatureManager::getInstance()->getVersion())
+ || (gSavedSettings.getS32("LastGPUClass") != LLFeatureManager::getInstance()->getGPUClass())
+ || (gSavedSettings.getBOOL("ProbeHardwareOnStartup")))
+ {
+ LLFeatureManager::getInstance()->applyRecommendedSettings();
+ gSavedSettings.setBOOL("ProbeHardwareOnStartup", FALSE);
+ }
+
+ if (!gGLManager.mHasDepthClamp)
+ {
+ LL_INFOS("RenderInit") << "Missing feature GL_ARB_depth_clamp. Void water might disappear in rare cases." << LL_ENDL;
+ }
+
+ // If we crashed while initializng GL stuff last time, disable certain features
+ if (gSavedSettings.getBOOL("RenderInitError"))
+ {
+ mInitAlert = "DisplaySettingsNoShaders";
+ LLFeatureManager::getInstance()->setGraphicsLevel(0, false);
+ gSavedSettings.setU32("RenderQualityPerformance", 0);
+ }
+
+ // Init the image list. Must happen after GL is initialized and before the images that
+ // LLViewerWindow needs are requested.
+ LLImageGL::initClass(LLViewerTexture::MAX_GL_IMAGE_CATEGORY) ;
+ gTextureList.init();
+ LLViewerTextureManager::init() ;
+ gBumpImageList.init();
+
+ // Init font system, but don't actually load the fonts yet
+ // because our window isn't onscreen and they take several
+ // seconds to parse.
+ LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"),
+ mDisplayScale.mV[VX],
+ mDisplayScale.mV[VY],
+ gDirUtilp->getAppRODataDir(),
+ LLUI::getXUIPaths());
+
+ // Create container for all sub-views
+ LLView::Params rvp;
+ rvp.name("root");
+ rvp.rect(mWindowRectScaled);
+ rvp.mouse_opaque(false);
+ rvp.follows.flags(FOLLOWS_NONE);
+ mRootView = LLUICtrlFactory::create<LLRootView>(rvp);
+ LLUI::setRootView(mRootView);
+
+ // Make avatar head look forward at start
+ mCurrentMousePoint.mX = getWindowWidthScaled() / 2;
+ mCurrentMousePoint.mY = getWindowHeightScaled() / 2;
+
+ gShowOverlayTitle = gSavedSettings.getBOOL("ShowOverlayTitle");
+ mOverlayTitle = gSavedSettings.getString("OverlayTitle");
+ // Can't have spaces in settings.ini strings, so use underscores instead and convert them.
+ LLStringUtil::replaceChar(mOverlayTitle, '_', ' ');
+
+ // sync the keyboard's setting with the saved setting
+ gSavedSettings.getControl("NumpadControl")->firePropertyChanged();
+
+ mDebugText = new LLDebugText(this);
+
+ mWorldViewRectScaled = calcScaledRect(mWorldViewRectRaw, mDisplayScale);
+}
+
+void LLViewerWindow::initGLDefaults()
+{
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
+
+ F32 ambient[4] = {0.f,0.f,0.f,0.f };
+ F32 diffuse[4] = {1.f,1.f,1.f,1.f };
+ glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,ambient);
+ glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,diffuse);
+
+ glPixelStorei(GL_PACK_ALIGNMENT,1);
+ glPixelStorei(GL_UNPACK_ALIGNMENT,1);
+
+ gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+
+ // lights for objects
+ glShadeModel( GL_SMOOTH );
+
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
+
+ gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+
+ glCullFace(GL_BACK);
+
+ // RN: Need this for translation and stretch manip.
+ gCone.prerender();
+ gBox.prerender();
+ gSphere.prerender();
+ gCylinder.prerender();
+}
+
+struct MainPanel : public LLPanel
+{
+};
+
+void LLViewerWindow::initBase()
+{
+ S32 height = getWindowHeightScaled();
+ S32 width = getWindowWidthScaled();
+
+ LLRect full_window(0, height, width, 0);
+
+ ////////////////////
+ //
+ // Set the gamma
+ //
+
+ F32 gamma = gSavedSettings.getF32("RenderGamma");
+ if (gamma != 0.0f)
+ {
+ getWindow()->setGamma(gamma);
+ }
+
+ // Create global views
+
+ // Create the floater view at the start so that other views can add children to it.
+ // (But wait to add it as a child of the root view so that it will be in front of the
+ // other views.)
+ MainPanel* main_view = new MainPanel();
+ main_view->buildFromFile("main_view.xml");
+ main_view->setShape(full_window);
+ getRootView()->addChild(main_view);
+
+ // placeholder widget that controls where "world" is rendered
+ mWorldViewPlaceholder = main_view->getChildView("world_view_rect")->getHandle();
+ mNonSideTrayView = main_view->getChildView("non_side_tray_view")->getHandle();
+ mFloaterViewHolder = main_view->getChildView("floater_view_holder")->getHandle();
+ mPopupView = main_view->getChild<LLPopupView>("popup_holder");
+ mHintHolder = main_view->getChild<LLView>("hint_holder")->getHandle();
+ mLoginPanelHolder = main_view->getChild<LLView>("login_panel_holder")->getHandle();
+
+ // Constrain floaters to inside the menu and status bar regions.
+ gFloaterView = main_view->getChild<LLFloaterView>("Floater View");
+ gFloaterView->setFloaterSnapView(main_view->getChild<LLView>("floater_snap_region")->getHandle());
+ gSnapshotFloaterView = main_view->getChild<LLSnapshotFloaterView>("Snapshot Floater View");
+
+
+ // Console
+ llassert( !gConsole );
+ LLConsole::Params cp;
+ cp.name("console");
+ cp.max_lines(gSavedSettings.getS32("ConsoleBufferSize"));
+ cp.rect(getChatConsoleRect());
+ cp.persist_time(gSavedSettings.getF32("ChatPersistTime"));
+ cp.font_size_index(gSavedSettings.getS32("ChatFontSize"));
+ cp.follows.flags(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM);
+ gConsole = LLUICtrlFactory::create<LLConsole>(cp);
+ getRootView()->addChild(gConsole);
+
+ // optionally forward warnings to chat console/chat floater
+ // for qa runs and dev builds
+#if !LL_RELEASE_FOR_DOWNLOAD
+ LLError::addRecorder(RecordToChatConsole::getInstance());
+#else
+ if(gSavedSettings.getBOOL("QAMode"))
+ {
+ LLError::addRecorder(RecordToChatConsole::getInstance());
+ }
+#endif
+
+ gDebugView = getRootView()->getChild<LLDebugView>("DebugView");
+ gDebugView->init();
+ gToolTipView = getRootView()->getChild<LLToolTipView>("tooltip view");
+
+ // Initialize busy response message when logged in
+ LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLFloaterPreference::initBusyResponse));
+
+ // Add the progress bar view (startup view), which overrides everything
+ mProgressView = getRootView()->findChild<LLProgressView>("progress_view");
+ setShowProgress(FALSE);
+ setProgressCancelButtonVisible(FALSE);
+
+ gMenuHolder = getRootView()->getChild<LLViewerMenuHolderGL>("Menu Holder");
+
+ LLMenuGL::sMenuContainer = gMenuHolder;
+
+}
+
+void LLViewerWindow::initWorldUI()
+{
+ S32 height = mRootView->getRect().getHeight();
+ S32 width = mRootView->getRect().getWidth();
+ LLRect full_window(0, height, width, 0);
+
+
+ gIMMgr = LLIMMgr::getInstance();
+
+ //getRootView()->sendChildToFront(gFloaterView);
+ //getRootView()->sendChildToFront(gSnapshotFloaterView);
+
+ // new bottom panel
+ LLPanel* bottom_tray_container = getRootView()->getChild<LLPanel>("bottom_tray_container");
+ LLBottomTray* bottom_tray = LLBottomTray::getInstance();
+ bottom_tray->setShape(bottom_tray_container->getLocalRect());
+ bottom_tray->setFollowsAll();
+ bottom_tray_container->addChild(bottom_tray);
+ bottom_tray_container->setVisible(TRUE);
+
+ LLRect morph_view_rect = full_window;
+ morph_view_rect.stretch( -STATUS_BAR_HEIGHT );
+ morph_view_rect.mTop = full_window.mTop - 32;
+ LLMorphView::Params mvp;
+ mvp.name("MorphView");
+ mvp.rect(morph_view_rect);
+ mvp.visible(false);
+ gMorphView = LLUICtrlFactory::create<LLMorphView>(mvp);
+ getRootView()->addChild(gMorphView);
+
+ LLWorldMapView::initClass();
+
+ // Force gFloaterWorldMap to initialize
+ LLFloaterReg::getInstance("world_map");
+
+ // Force gFloaterTools to initialize
+ LLFloaterReg::getInstance("build");
+ LLFloaterReg::hideInstance("build");
+
+ // Status bar
+ LLPanel* status_bar_container = getRootView()->getChild<LLPanel>("status_bar_container");
+ gStatusBar = new LLStatusBar(status_bar_container->getLocalRect());
+ gStatusBar->setFollowsAll();
+ gStatusBar->setShape(status_bar_container->getLocalRect());
+ // sync bg color with menu bar
+ gStatusBar->setBackgroundColor( gMenuBarView->getBackgroundColor().get() );
+ status_bar_container->addChild(gStatusBar);
+ status_bar_container->setVisible(TRUE);
+
+ // Navigation bar
+ LLPanel* nav_bar_container = getRootView()->getChild<LLPanel>("nav_bar_container");
+
+ LLNavigationBar* navbar = LLNavigationBar::getInstance();
+ navbar->setShape(nav_bar_container->getLocalRect());
+ navbar->setBackgroundColor(gMenuBarView->getBackgroundColor().get());
+ nav_bar_container->addChild(navbar);
+ nav_bar_container->setVisible(TRUE);
+
+ if (!gSavedSettings.getBOOL("ShowNavbarNavigationPanel"))
+ {
+ navbar->showNavigationPanel(FALSE);
+ }
+
+ if (!gSavedSettings.getBOOL("ShowNavbarFavoritesPanel"))
+ {
+ navbar->showFavoritesPanel(FALSE);
+ }
+
+ // Top Info bar
+ LLPanel* topinfo_bar_container = getRootView()->getChild<LLPanel>("topinfo_bar_container");
+ LLPanelTopInfoBar* topinfo_bar = LLPanelTopInfoBar::getInstance();
+
+ topinfo_bar->setShape(topinfo_bar_container->getLocalRect());
+
+ topinfo_bar_container->addChild(topinfo_bar);
+ topinfo_bar_container->setVisible(TRUE);
+
+ if (!gSavedSettings.getBOOL("ShowMiniLocationPanel"))
+ {
+ topinfo_bar->setVisible(FALSE);
+ }
+
+ if ( gHUDView == NULL )
+ {
+ LLRect hud_rect = full_window;
+ hud_rect.mBottom += 50;
+ if (gMenuBarView && gMenuBarView->isInVisibleChain())
+ {
+ hud_rect.mTop -= gMenuBarView->getRect().getHeight();
+ }
+ gHUDView = new LLHUDView(hud_rect);
+ // put behind everything else in the UI
+ getRootView()->addChildInBack(gHUDView);
+ }
+
+ LLPanel* panel_ssf_container = getRootView()->getChild<LLPanel>("stand_stop_flying_container");
+ LLPanelStandStopFlying* panel_stand_stop_flying = LLPanelStandStopFlying::getInstance();
+ panel_ssf_container->addChild(panel_stand_stop_flying);
+ panel_ssf_container->setVisible(TRUE);
+
+ // put sidetray in container
+ LLPanel* side_tray_container = getRootView()->getChild<LLPanel>("side_tray_container");
+ LLSideTray* sidetrayp = LLSideTray::getInstance();
+ sidetrayp->setShape(side_tray_container->getLocalRect());
+ // don't follow right edge to avoid spurious resizes, since we are using a fixed width layout
+ sidetrayp->setFollows(FOLLOWS_LEFT|FOLLOWS_TOP|FOLLOWS_BOTTOM);
+ side_tray_container->addChild(sidetrayp);
+ side_tray_container->setVisible(FALSE);
+
+ // put sidetray buttons in their own panel
+ LLPanel* buttons_panel = sidetrayp->getButtonsPanel();
+ LLPanel* buttons_panel_container = getRootView()->getChild<LLPanel>("side_bar_tabs");
+ buttons_panel->setShape(buttons_panel_container->getLocalRect());
+ buttons_panel->setFollowsAll();
+ buttons_panel_container->addChild(buttons_panel);
+
+ LLView* avatar_picker_destination_guide_container = gViewerWindow->getRootView()->getChild<LLView>("avatar_picker_and_destination_guide_container");
+ avatar_picker_destination_guide_container->getChild<LLButton>("close")->setCommitCallback(boost::bind(toggle_destination_and_avatar_picker, LLSD()));
+ LLMediaCtrl* destinations = avatar_picker_destination_guide_container->findChild<LLMediaCtrl>("destination_guide_contents");
+ LLMediaCtrl* avatar_picker = avatar_picker_destination_guide_container->findChild<LLMediaCtrl>("avatar_picker_contents");
+ if (destinations)
+ {
+ destinations->navigateTo(gSavedSettings.getString("DestinationGuideURL"), "text/html");
+ }
+
+ if (avatar_picker)
+ {
+ avatar_picker->navigateTo(gSavedSettings.getString("AvatarPickerURL"), "text/html");
+ }
+
+ if (gSavedSettings.getBOOL("FirstRunThisInstall"))
+ {
+ toggle_destination_and_avatar_picker(0);
+ }
+
+ gSavedSettings.setBOOL("FirstRunThisInstall", FALSE);
+}
+
+// Destroy the UI
+void LLViewerWindow::shutdownViews()
+{
+ // clean up warning logger
+ LLError::removeRecorder(RecordToChatConsole::getInstance());
+
+ delete mDebugText;
+ mDebugText = NULL;
+
+ // Cleanup global views
+ if (gMorphView)
+ {
+ gMorphView->setVisible(FALSE);
+ }
+
+ // DEV-40930: Clear sModalStack. Otherwise, any LLModalDialog left open
+ // will crump with LL_ERRS.
+ LLModalDialog::shutdownModals();
+
+ // destroy the nav bar, not currently part of gViewerWindow
+ // *TODO: Make LLNavigationBar part of gViewerWindow
+ delete LLNavigationBar::getInstance();
+
+ // destroy menus after instantiating navbar above, as it needs
+ // access to gMenuHolder
+ cleanup_menus();
+
+ // Delete all child views.
+ delete mRootView;
+ mRootView = NULL;
+
+ // Automatically deleted as children of mRootView. Fix the globals.
+ gStatusBar = NULL;
+ gIMMgr = NULL;
+ gToolTipView = NULL;
+
+ gFloaterView = NULL;
+ gMorphView = NULL;
+
+ gHUDView = NULL;
+}
+
+void LLViewerWindow::shutdownGL()
+{
+ //--------------------------------------------------------
+ // Shutdown GL cleanly. Order is very important here.
+ //--------------------------------------------------------
+ LLFontGL::destroyDefaultFonts();
+ LLFontManager::cleanupClass();
+ stop_glerror();
+
+ gSky.cleanup();
+ stop_glerror();
+
+ LLWearableList::instance().cleanup() ;
+
+ gTextureList.shutdown();
+ stop_glerror();
+
+ gBumpImageList.shutdown();
+ stop_glerror();
+
+ LLWorldMapView::cleanupTextures();
+
+ llinfos << "Cleaning up pipeline" << llendl;
+ gPipeline.cleanup();
+ stop_glerror();
+
+ LLViewerTextureManager::cleanup() ;
+ LLImageGL::cleanupClass() ;
+
+ llinfos << "All textures and llimagegl images are destroyed!" << llendl ;
+
+ llinfos << "Cleaning up select manager" << llendl;
+ LLSelectMgr::getInstance()->cleanup();
+
+ LLVertexBuffer::cleanupClass();
+
+ llinfos << "Stopping GL during shutdown" << llendl;
+ if (!gNoRender)
+ {
+ stopGL(FALSE);
+ stop_glerror();
+ }
+
+ gGL.shutdown();
+}
+
+// shutdownViews() and shutdownGL() need to be called first
+LLViewerWindow::~LLViewerWindow()
+{
+ llinfos << "Destroying Window" << llendl;
+ destroyWindow();
+
+ delete mDebugText;
+ mDebugText = NULL;
+}
+
+
+void LLViewerWindow::setCursor( ECursorType c )
+{
+ mWindow->setCursor( c );
+}
+
+void LLViewerWindow::showCursor()
+{
+ mWindow->showCursor();
+
+ mCursorHidden = FALSE;
+}
+
+void LLViewerWindow::hideCursor()
+{
+ // And hide the cursor
+ mWindow->hideCursor();
+
+ mCursorHidden = TRUE;
+}
+
+void LLViewerWindow::sendShapeToSim()
+{
+ LLMessageSystem* msg = gMessageSystem;
+ if(!msg) return;
+ msg->newMessageFast(_PREHASH_AgentHeightWidth);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addU32Fast(_PREHASH_CircuitCode, gMessageSystem->mOurCircuitCode);
+ msg->nextBlockFast(_PREHASH_HeightWidthBlock);
+ msg->addU32Fast(_PREHASH_GenCounter, 0);
+ U16 height16 = (U16) mWorldViewRectRaw.getHeight();
+ U16 width16 = (U16) mWorldViewRectRaw.getWidth();
+ msg->addU16Fast(_PREHASH_Height, height16);
+ msg->addU16Fast(_PREHASH_Width, width16);
+ gAgent.sendReliableMessage();
+}
+
+// Must be called after window is created to set up agent
+// camera variables and UI variables.
+void LLViewerWindow::reshape(S32 width, S32 height)
+{
+ // Destroying the window at quit time generates spurious
+ // reshape messages. We don't care about these, and we
+ // don't want to send messages because the message system
+ // may have been destructed.
+ if (!LLApp::isExiting())
+ {
+ if (gNoRender)
+ {
+ return;
+ }
+
+ gWindowResized = TRUE;
+
+ // update our window rectangle
+ mWindowRectRaw.mRight = mWindowRectRaw.mLeft + width;
+ mWindowRectRaw.mTop = mWindowRectRaw.mBottom + height;
+
+ //glViewport(0, 0, width, height );
+
+ if (height > 0)
+ {
+ LLViewerCamera::getInstance()->setViewHeightInPixels( mWorldViewRectRaw.getHeight() );
+ LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() );
+ }
+
+ calcDisplayScale();
+
+ BOOL display_scale_changed = mDisplayScale != LLUI::sGLScaleFactor;
+ LLUI::setScaleFactor(mDisplayScale);
+
+ // update our window rectangle
+ mWindowRectScaled.mRight = mWindowRectScaled.mLeft + llround((F32)width / mDisplayScale.mV[VX]);
+ mWindowRectScaled.mTop = mWindowRectScaled.mBottom + llround((F32)height / mDisplayScale.mV[VY]);
+
+ setup2DViewport();
+
+ // Inform lower views of the change
+ // round up when converting coordinates to make sure there are no gaps at edge of window
+ LLView::sForceReshape = display_scale_changed;
+ mRootView->reshape(llceil((F32)width / mDisplayScale.mV[VX]), llceil((F32)height / mDisplayScale.mV[VY]));
+ LLView::sForceReshape = FALSE;
+
+ // clear font width caches
+ if (display_scale_changed)
+ {
+ LLHUDObject::reshapeAll();
+ }
+
+ sendShapeToSim();
+
+ // store new settings for the mode we are in, regardless
+ // Only save size if not maximized
+ BOOL maximized = mWindow->getMaximized();
+ gSavedSettings.setBOOL("WindowMaximized", maximized);
+
+ LLCoordScreen window_size;
+ if (!maximized
+ && mWindow->getSize(&window_size))
+ {
+ gSavedSettings.setS32("WindowWidth", window_size.mX);
+ gSavedSettings.setS32("WindowHeight", window_size.mY);
+ }
+
+ LLViewerStats::getInstance()->setStat(LLViewerStats::ST_WINDOW_WIDTH, (F64)width);
+ LLViewerStats::getInstance()->setStat(LLViewerStats::ST_WINDOW_HEIGHT, (F64)height);
+ }
+}
+
+
+// Hide normal UI when a logon fails
+void LLViewerWindow::setNormalControlsVisible( BOOL visible )
+{
+ if(LLBottomTray::instanceExists())
+ {
+ LLBottomTray::getInstance()->setVisible(visible);
+ LLBottomTray::getInstance()->setEnabled(visible);
+ }
+
+ if ( gMenuBarView )
+ {
+ gMenuBarView->setVisible( visible );
+ gMenuBarView->setEnabled( visible );
+
+ // ...and set the menu color appropriately.
+ setMenuBackgroundColor(gAgent.getGodLevel() > GOD_NOT,
+ LLGridManager::getInstance()->isInProductionGrid());
+ }
+
+ if ( gStatusBar )
+ {
+ gStatusBar->setVisible( visible );
+ gStatusBar->setEnabled( visible );
+ }
+
+ LLNavigationBar* navbarp = LLUI::getRootView()->findChild<LLNavigationBar>("navigation_bar");
+ if (navbarp)
+ {
+ navbarp->setVisible( visible );
+ }
+}
+
+void LLViewerWindow::setMenuBackgroundColor(bool god_mode, bool dev_grid)
+{
+ LLSD args;
+ LLColor4 new_bg_color;
+
+ // no l10n problem because channel is always an english string
+ std::string channel = LLVersionInfo::getChannel();
+ bool isProject = (channel.find("Project") != std::string::npos);
+
+ // god more important than project, proj more important than grid
+ if(god_mode && LLGridManager::getInstance()->isInProductionGrid())
+ {
+ new_bg_color = LLUIColorTable::instance().getColor( "MenuBarGodBgColor" );
+ }
+ else if(god_mode && !LLGridManager::getInstance()->isInProductionGrid())
+ {
+ new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionGodBgColor" );
+ }
+ else if (!god_mode && isProject)
+ {
+ new_bg_color = LLUIColorTable::instance().getColor( "MenuBarProjectBgColor" );
+ }
+ else if(!god_mode && !LLGridManager::getInstance()->isInProductionGrid())
+ {
+ new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" );
+ }
+ else
+ {
+ new_bg_color = LLUIColorTable::instance().getColor( "MenuBarBgColor" );
+ }
+
+ if(gMenuBarView)
+ {
+ gMenuBarView->setBackgroundColor( new_bg_color );
+ }
+
+ if(gStatusBar)
+ {
+ gStatusBar->setBackgroundColor( new_bg_color );
+ }
+}
+
+void LLViewerWindow::drawDebugText()
+{
+ gGL.color4f(1,1,1,1);
+ gGL.pushMatrix();
+ gGL.pushUIMatrix();
+ {
+ // scale view by UI global scale factor and aspect ratio correction factor
+ gGL.scaleUI(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f);
+ mDebugText->draw();
+ }
+ gGL.popUIMatrix();
+ gGL.popMatrix();
+
+ gGL.flush();
+}
+
+void LLViewerWindow::draw()
+{
+
+//#if LL_DEBUG
+ LLView::sIsDrawing = TRUE;
+//#endif
+ stop_glerror();
+
+ LLUI::setLineWidth(1.f);
+
+ LLUI::setLineWidth(1.f);
+ // Reset any left-over transforms
+ glMatrixMode(GL_MODELVIEW);
+
+ glLoadIdentity();
+
+ //S32 screen_x, screen_y;
+
+ if (!gSavedSettings.getBOOL("RenderUIBuffer"))
+ {
+ LLUI::sDirtyRect = getWindowRectScaled();
+ }
+
+ // HACK for timecode debugging
+ if (gSavedSettings.getBOOL("DisplayTimecode"))
+ {
+ // draw timecode block
+ std::string text;
+
+ glLoadIdentity();
+
+ microsecondsToTimecodeString(gFrameTime,text);
+ const LLFontGL* font = LLFontGL::getFontSansSerif();
+ font->renderUTF8(text, 0,
+ llround((getWindowWidthScaled()/2)-100.f),
+ llround((getWindowHeightScaled()-60.f)),
+ LLColor4( 1.f, 1.f, 1.f, 1.f ),
+ LLFontGL::LEFT, LLFontGL::TOP);
+ }
+
+ // Draw all nested UI views.
+ // No translation needed, this view is glued to 0,0
+
+ gGL.pushMatrix();
+ LLUI::pushMatrix();
+ {
+
+ // scale view by UI global scale factor and aspect ratio correction factor
+ gGL.scaleUI(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f);
+
+ LLVector2 old_scale_factor = LLUI::sGLScaleFactor;
+ // apply camera zoom transform (for high res screenshots)
+ F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor();
+ S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion();
+ if (zoom_factor > 1.f)
+ {
+ //decompose subregion number to x and y values
+ int pos_y = sub_region / llceil(zoom_factor);
+ int pos_x = sub_region - (pos_y*llceil(zoom_factor));
+ // offset for this tile
+ glTranslatef((F32)getWindowWidthScaled() * -(F32)pos_x,
+ (F32)getWindowHeightScaled() * -(F32)pos_y,
+ 0.f);
+ glScalef(zoom_factor, zoom_factor, 1.f);
+ LLUI::sGLScaleFactor *= zoom_factor;
+ }
+
+ // Draw tool specific overlay on world
+ LLToolMgr::getInstance()->getCurrentTool()->draw();
+
+ if( gAgentCamera.cameraMouselook() || LLFloaterCamera::inFreeCameraMode() )
+ {
+ drawMouselookInstructions();
+ stop_glerror();
+ }
+
+ // Draw all nested UI views.
+ // No translation needed, this view is glued to 0,0
+ mRootView->draw();
+
+ if (LLView::sDebugRects)
+ {
+ gToolTipView->drawStickyRect();
+ }
+
+ // Draw optional on-top-of-everyone view
+ LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
+ if (top_ctrl && top_ctrl->getVisible())
+ {
+ S32 screen_x, screen_y;
+ top_ctrl->localPointToScreen(0, 0, &screen_x, &screen_y);
+
+ glMatrixMode(GL_MODELVIEW);
+ LLUI::pushMatrix();
+ LLUI::translate( (F32) screen_x, (F32) screen_y, 0.f);
+ top_ctrl->draw();
+ LLUI::popMatrix();
+ }
+
+
+ if( gShowOverlayTitle && !mOverlayTitle.empty() )
+ {
+ // Used for special titles such as "Second Life - Special E3 2003 Beta"
+ const S32 DIST_FROM_TOP = 20;
+ LLFontGL::getFontSansSerifBig()->renderUTF8(
+ mOverlayTitle, 0,
+ llround( getWindowWidthScaled() * 0.5f),
+ getWindowHeightScaled() - DIST_FROM_TOP,
+ LLColor4(1, 1, 1, 0.4f),
+ LLFontGL::HCENTER, LLFontGL::TOP);
+ }
+
+ LLUI::sGLScaleFactor = old_scale_factor;
+ }
+ LLUI::popMatrix();
+ gGL.popMatrix();
+
+//#if LL_DEBUG
+ LLView::sIsDrawing = FALSE;
+//#endif
+}
+
+// Takes a single keydown event, usually when UI is visible
+BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
+{
+ // hide tooltips on keypress
+ LLToolTipMgr::instance().blockToolTips();
+
+ if (gFocusMgr.getKeyboardFocus()
+ && !(mask & (MASK_CONTROL | MASK_ALT))
+ && !gFocusMgr.getKeystrokesOnly())
+ {
+ // We have keyboard focus, and it's not an accelerator
+ if (key < 0x80)
+ {
+ // Not a special key, so likely (we hope) to generate a character. Let it fall through to character handler first.
+ return (gFocusMgr.getKeyboardFocus() != NULL);
+ }
+ }
+
+ // let menus handle navigation keys for navigation
+ if ((gMenuBarView && gMenuBarView->handleKey(key, mask, TRUE))
+ ||(gLoginMenuBarView && gLoginMenuBarView->handleKey(key, mask, TRUE))
+ ||(gMenuHolder && gMenuHolder->handleKey(key, mask, TRUE)))
+ {
+ return TRUE;
+ }
+
+ LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
+
+ // give menus a chance to handle modified (Ctrl, Alt) shortcut keys before current focus
+ // as long as focus isn't locked
+ if (mask & (MASK_CONTROL | MASK_ALT) && !gFocusMgr.focusLocked())
+ {
+ // Check the current floater's menu first, if it has one.
+ if (gFocusMgr.keyboardFocusHasAccelerators()
+ && keyboard_focus
+ && keyboard_focus->handleKey(key,mask,FALSE))
+ {
+ return TRUE;
+ }
+
+ if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask))
+ ||(gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask)))
+ {
+ return TRUE;
+ }
+ }
+
+ // give floaters first chance to handle TAB key
+ // so frontmost floater gets focus
+ // if nothing has focus, go to first or last UI element as appropriate
+ if (key == KEY_TAB && (mask & MASK_CONTROL || gFocusMgr.getKeyboardFocus() == NULL))
+ {
+ if (gMenuHolder) gMenuHolder->hideMenus();
+
+ // if CTRL-tabbing (and not just TAB with no focus), go into window cycle mode
+ gFloaterView->setCycleMode((mask & MASK_CONTROL) != 0);
+
+ // do CTRL-TAB and CTRL-SHIFT-TAB logic
+ if (mask & MASK_SHIFT)
+ {
+ mRootView->focusPrevRoot();
+ }
+ else
+ {
+ mRootView->focusNextRoot();
+ }
+ return TRUE;
+ }
+ // hidden edit menu for cut/copy/paste
+ if (gEditMenu && gEditMenu->handleAcceleratorKey(key, mask))
+ {
+ return TRUE;
+ }
+
+ // Traverses up the hierarchy
+ if( keyboard_focus )
+ {
+ LLLineEditor* chat_editor = LLBottomTray::instanceExists() ? LLBottomTray::getInstance()->getNearbyChatBar()->getChatBox() : NULL;
+ // arrow keys move avatar while chatting hack
+ if (chat_editor && chat_editor->hasFocus())
+ {
+ // If text field is empty, there's no point in trying to move
+ // cursor with arrow keys, so allow movement
+ if (chat_editor->getText().empty()
+ || gSavedSettings.getBOOL("ArrowKeysAlwaysMove"))
+ {
+ // let Control-Up and Control-Down through for chat line history,
+ if (!(key == KEY_UP && mask == MASK_CONTROL)
+ && !(key == KEY_DOWN && mask == MASK_CONTROL))
+ {
+ switch(key)
+ {
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_PAGE_UP:
+ case KEY_PAGE_DOWN:
+ case KEY_HOME:
+ // when chatbar is empty or ArrowKeysAlwaysMove set,
+ // pass arrow keys on to avatar...
+ return FALSE;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ if (keyboard_focus->handleKey(key, mask, FALSE))
+ {
+ return TRUE;
+ }
+ }
+
+ if( LLToolMgr::getInstance()->getCurrentTool()->handleKey(key, mask) )
+ {
+ return TRUE;
+ }
+
+ // Try for a new-format gesture
+ if (LLGestureMgr::instance().triggerGesture(key, mask))
+ {
+ return TRUE;
+ }
+
+ // See if this is a gesture trigger. If so, eat the key and
+ // don't pass it down to the menus.
+ if (gGestureList.trigger(key, mask))
+ {
+ return TRUE;
+ }
+
+ // If "Pressing letter keys starts local chat" option is selected, we are not in mouselook,
+ // no view has keyboard focus, this is a printable character key (and no modifier key is
+ // pressed except shift), then give focus to nearby chat (STORM-560)
+ if ( gSavedSettings.getS32("LetterKeysFocusChatBar") && !gAgentCamera.cameraMouselook() &&
+ !keyboard_focus && key < 0x80 && (mask == MASK_NONE || mask == MASK_SHIFT) )
+ {
+ LLLineEditor* chat_editor = LLBottomTray::instanceExists() ? LLBottomTray::getInstance()->getNearbyChatBar()->getChatBox() : NULL;
+ if (chat_editor)
+ {
+ // passing NULL here, character will be added later when it is handled by character handler.
+ LLBottomTray::getInstance()->getNearbyChatBar()->startChat(NULL);
+ return TRUE;
+ }
+ }
+
+ // give menus a chance to handle unmodified accelerator keys
+ if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask))
+ ||(gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask)))
+ {
+ return TRUE;
+ }
+
+ // don't pass keys on to world when something in ui has focus
+ return gFocusMgr.childHasKeyboardFocus(mRootView)
+ || LLMenuGL::getKeyboardMode()
+ || (gMenuBarView && gMenuBarView->getHighlightedItem() && gMenuBarView->getHighlightedItem()->isActive());
+}
+
+
+BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
+{
+ // HACK: We delay processing of return keys until they arrive as a Unicode char,
+ // so that if you're typing chat text at low frame rate, we don't send the chat
+ // until all keystrokes have been entered. JC
+ // HACK: Numeric keypad <enter> on Mac is Unicode 3
+ // HACK: Control-M on Windows is Unicode 13
+ if ((uni_char == 13 && mask != MASK_CONTROL)
+ || (uni_char == 3 && mask == MASK_NONE))
+ {
+ return gViewerKeyboard.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN));
+ }
+
+ // let menus handle navigation (jump) keys
+ if (gMenuBarView && gMenuBarView->handleUnicodeChar(uni_char, TRUE))
+ {
+ return TRUE;
+ }
+
+ // Traverses up the hierarchy
+ LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
+ if( keyboard_focus )
+ {
+ if (keyboard_focus->handleUnicodeChar(uni_char, FALSE))
+ {
+ return TRUE;
+ }
+
+ //// Topmost view gets a chance before the hierarchy
+ //LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
+ //if (top_ctrl && top_ctrl->handleUnicodeChar( uni_char, FALSE ) )
+ //{
+ // return TRUE;
+ //}
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+void LLViewerWindow::handleScrollWheel(S32 clicks)
+{
+ LLView::sMouseHandlerMessage.clear();
+
+ LLUI::resetMouseIdleTimer();
+
+ LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
+ if( mouse_captor )
+ {
+ S32 local_x;
+ S32 local_y;
+ mouse_captor->screenPointToLocal( mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y );
+ mouse_captor->handleScrollWheel(local_x, local_y, clicks);
+ if (LLView::sDebugMouseHandling)
+ {
+ llinfos << "Scroll Wheel handled by captor " << mouse_captor->getName() << llendl;
+ }
+ return;
+ }
+
+ LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
+ if (top_ctrl)
+ {
+ S32 local_x;
+ S32 local_y;
+ top_ctrl->screenPointToLocal( mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y );
+ if (top_ctrl->handleScrollWheel(local_x, local_y, clicks)) return;
+ }
+
+ if (mRootView->handleScrollWheel(mCurrentMousePoint.mX, mCurrentMousePoint.mY, clicks) )
+ {
+ if (LLView::sDebugMouseHandling)
+ {
+ llinfos << "Scroll Wheel" << LLView::sMouseHandlerMessage << llendl;
+ }
+ return;
+ }
+ else if (LLView::sDebugMouseHandling)
+ {
+ llinfos << "Scroll Wheel not handled by view" << llendl;
+ }
+
+ // Zoom the camera in and out behavior
+
+ if(top_ctrl == 0
+ && getWorldViewRectScaled().pointInRect(mCurrentMousePoint.mX, mCurrentMousePoint.mY)
+ && gAgentCamera.isInitialized())
+ gAgentCamera.handleScrollWheel(clicks);
+
+ return;
+}
+
+void LLViewerWindow::addPopup(LLView* popup)
+{
+ if (mPopupView)
+ {
+ mPopupView->addPopup(popup);
+ }
+}
+
+void LLViewerWindow::removePopup(LLView* popup)
+{
+ if (mPopupView)
+ {
+ mPopupView->removePopup(popup);
+ }
+}
+
+void LLViewerWindow::clearPopups()
+{
+ if (mPopupView)
+ {
+ mPopupView->clearPopups();
+ }
+}
+
+void LLViewerWindow::moveCursorToCenter()
+{
+ if (! gSavedSettings.getBOOL("DisableMouseWarp"))
+ {
+ S32 x = getWorldViewWidthScaled() / 2;
+ S32 y = getWorldViewHeightScaled() / 2;
+
+ //on a forced move, all deltas get zeroed out to prevent jumping
+ mCurrentMousePoint.set(x,y);
+ mLastMousePoint.set(x,y);
+ mCurrentMouseDelta.set(0,0);
+
+ LLUI::setMousePositionScreen(x, y);
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Hover handlers
+//
+
+void append_xui_tooltip(LLView* viewp, LLToolTip::Params& params)
+{
+ if (viewp)
+ {
+ if (!params.styled_message.empty())
+ {
+ params.styled_message.add().text("\n---------\n");
+ }
+ LLView::root_to_view_iterator_t end_tooltip_it = viewp->endRootToView();
+ // NOTE: we skip "root" since it is assumed
+ for (LLView::root_to_view_iterator_t tooltip_it = ++viewp->beginRootToView();
+ tooltip_it != end_tooltip_it;
+ ++tooltip_it)
+ {
+ LLView* viewp = *tooltip_it;
+
+ params.styled_message.add().text(viewp->getName());
+
+ LLPanel* panelp = dynamic_cast<LLPanel*>(viewp);
+ if (panelp && !panelp->getXMLFilename().empty())
+ {
+ params.styled_message.add()
+ .text("(" + panelp->getXMLFilename() + ")")
+ .style.color(LLColor4(0.7f, 0.7f, 1.f, 1.f));
+ }
+ params.styled_message.add().text("/");
+ }
+ }
+}
+
+// Update UI based on stored mouse position from mouse-move
+// event processing.
+void LLViewerWindow::updateUI()
+{
+ static LLFastTimer::DeclareTimer ftm("Update UI");
+ LLFastTimer t(ftm);
+
+ static std::string last_handle_msg;
+
+ if (gLoggedInTime.getStarted())
+ {
+ if (gLoggedInTime.getElapsedTimeF32() > gSavedSettings.getF32("DestinationGuideHintTimeout"))
+ {
+ LLFirstUse::notUsingDestinationGuide();
+ }
+ if (gLoggedInTime.getElapsedTimeF32() > gSavedSettings.getF32("SidePanelHintTimeout"))
+ {
+ LLFirstUse::notUsingSidePanel();
+ }
+ }
+
+ LLConsole::updateClass();
+
+ // animate layout stacks so we have up to date rect for world view
+ LLLayoutStack::updateClass();
+
+ // use full window for world view when not rendering UI
+ bool world_view_uses_full_window = gAgentCamera.cameraMouselook() || !gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
+ updateWorldViewRect(world_view_uses_full_window);
+
+ LLView::sMouseHandlerMessage.clear();
+
+ S32 x = mCurrentMousePoint.mX;
+ S32 y = mCurrentMousePoint.mY;
+ MASK mask = gKeyboard->currentMask(TRUE);
+
+ if (gNoRender)
+ {
+ return;
+ }
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST))
+ {
+ gDebugRaycastFaceHit = -1;
+ gDebugRaycastObject = cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE,
+ &gDebugRaycastFaceHit,
+ &gDebugRaycastIntersection,
+ &gDebugRaycastTexCoord,
+ &gDebugRaycastNormal,
+ &gDebugRaycastBinormal);
+ }
+
+ updateMouseDelta();
+ updateKeyboardFocus();
+
+ BOOL handled = FALSE;
+
+ BOOL handled_by_top_ctrl = FALSE;
+ LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
+ LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
+ LLView* captor_view = dynamic_cast<LLView*>(mouse_captor);
+
+ //FIXME: only include captor and captor's ancestors if mouse is truly over them --RN
+
+ //build set of views containing mouse cursor by traversing UI hierarchy and testing
+ //screen rect against mouse cursor
+ view_handle_set_t mouse_hover_set;
+
+ // constraint mouse enter events to children of mouse captor
+ LLView* root_view = captor_view;
+
+ // if mouse captor doesn't exist or isn't a LLView
+ // then allow mouse enter events on entire UI hierarchy
+ if (!root_view)
+ {
+ root_view = mRootView;
+ }
+
+ // only update mouse hover set when UI is visible (since we shouldn't send hover events to invisible UI
+ if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+ // include all ancestors of captor_view as automatically having mouse
+ if (captor_view)
+ {
+ LLView* captor_parent_view = captor_view->getParent();
+ while(captor_parent_view)
+ {
+ mouse_hover_set.insert(captor_parent_view->getHandle());
+ captor_parent_view = captor_parent_view->getParent();
+ }
+ }
+
+ // aggregate visible views that contain mouse cursor in display order
+ LLPopupView::popup_list_t popups = mPopupView->getCurrentPopups();
+
+ for(LLPopupView::popup_list_t::iterator popup_it = popups.begin(); popup_it != popups.end(); ++popup_it)
+ {
+ LLView* popup = popup_it->get();
+ if (popup && popup->calcScreenBoundingRect().pointInRect(x, y))
+ {
+ // iterator over contents of top_ctrl, and throw into mouse_hover_set
+ for (LLView::tree_iterator_t it = popup->beginTreeDFS();
+ it != popup->endTreeDFS();
+ ++it)
+ {
+ LLView* viewp = *it;
+ if (viewp->getVisible()
+ && viewp->calcScreenBoundingRect().pointInRect(x, y))
+ {
+ // we have a view that contains the mouse, add it to the set
+ mouse_hover_set.insert(viewp->getHandle());
+ }
+ else
+ {
+ // skip this view and all of its children
+ it.skipDescendants();
+ }
+ }
+ }
+ }
+
+ // while the top_ctrl contains the mouse cursor, only it and its descendants will receive onMouseEnter events
+ if (top_ctrl && top_ctrl->calcScreenBoundingRect().pointInRect(x, y))
+ {
+ // iterator over contents of top_ctrl, and throw into mouse_hover_set
+ for (LLView::tree_iterator_t it = top_ctrl->beginTreeDFS();
+ it != top_ctrl->endTreeDFS();
+ ++it)
+ {
+ LLView* viewp = *it;
+ if (viewp->getVisible()
+ && viewp->calcScreenBoundingRect().pointInRect(x, y))
+ {
+ // we have a view that contains the mouse, add it to the set
+ mouse_hover_set.insert(viewp->getHandle());
+ }
+ else
+ {
+ // skip this view and all of its children
+ it.skipDescendants();
+ }
+ }
+ }
+ else
+ {
+ // walk UI tree in depth-first order
+ for (LLView::tree_iterator_t it = root_view->beginTreeDFS();
+ it != root_view->endTreeDFS();
+ ++it)
+ {
+ LLView* viewp = *it;
+ // calculating the screen rect involves traversing the parent, so this is less than optimal
+ if (viewp->getVisible()
+ && viewp->calcScreenBoundingRect().pointInRect(x, y))
+ {
+
+ // if this view is mouse opaque, nothing behind it should be in mouse_hover_set
+ if (viewp->getMouseOpaque())
+ {
+ // constrain further iteration to children of this widget
+ it = viewp->beginTreeDFS();
+ }
+
+ // we have a view that contains the mouse, add it to the set
+ mouse_hover_set.insert(viewp->getHandle());
+ }
+ else
+ {
+ // skip this view and all of its children
+ it.skipDescendants();
+ }
+ }
+ }
+ }
+
+ typedef std::vector<LLHandle<LLView> > view_handle_list_t;
+
+ // call onMouseEnter() on all views which contain the mouse cursor but did not before
+ view_handle_list_t mouse_enter_views;
+ std::set_difference(mouse_hover_set.begin(), mouse_hover_set.end(),
+ mMouseHoverViews.begin(), mMouseHoverViews.end(),
+ std::back_inserter(mouse_enter_views));
+ for (view_handle_list_t::iterator it = mouse_enter_views.begin();
+ it != mouse_enter_views.end();
+ ++it)
+ {
+ LLView* viewp = it->get();
+ if (viewp)
+ {
+ LLRect view_screen_rect = viewp->calcScreenRect();
+ viewp->onMouseEnter(x - view_screen_rect.mLeft, y - view_screen_rect.mBottom, mask);
+ }
+ }
+
+ // call onMouseLeave() on all views which no longer contain the mouse cursor
+ view_handle_list_t mouse_leave_views;
+ std::set_difference(mMouseHoverViews.begin(), mMouseHoverViews.end(),
+ mouse_hover_set.begin(), mouse_hover_set.end(),
+ std::back_inserter(mouse_leave_views));
+ for (view_handle_list_t::iterator it = mouse_leave_views.begin();
+ it != mouse_leave_views.end();
+ ++it)
+ {
+ LLView* viewp = it->get();
+ if (viewp)
+ {
+ LLRect view_screen_rect = viewp->calcScreenRect();
+ viewp->onMouseLeave(x - view_screen_rect.mLeft, y - view_screen_rect.mBottom, mask);
+ }
+ }
+
+ // store resulting hover set for next frame
+ swap(mMouseHoverViews, mouse_hover_set);
+
+ // only handle hover events when UI is enabled
+ if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+
+ if( mouse_captor )
+ {
+ // Pass hover events to object capturing mouse events.
+ S32 local_x;
+ S32 local_y;
+ mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
+ handled = mouse_captor->handleHover(local_x, local_y, mask);
+ if (LLView::sDebugMouseHandling)
+ {
+ llinfos << "Hover handled by captor " << mouse_captor->getName() << llendl;
+ }
+
+ if( !handled )
+ {
+ lldebugst(LLERR_USER_INPUT) << "hover not handled by mouse captor" << llendl;
+ }
+ }
+ else
+ {
+ if (top_ctrl)
+ {
+ S32 local_x, local_y;
+ top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
+ handled = top_ctrl->pointInView(local_x, local_y) && top_ctrl->handleHover(local_x, local_y, mask);
+ handled_by_top_ctrl = TRUE;
+ }
+
+ if ( !handled )
+ {
+ // x and y are from last time mouse was in window
+ // mMouseInWindow tracks *actual* mouse location
+ if (mMouseInWindow && mRootView->handleHover(x, y, mask) )
+ {
+ if (LLView::sDebugMouseHandling && LLView::sMouseHandlerMessage != last_handle_msg)
+ {
+ last_handle_msg = LLView::sMouseHandlerMessage;
+ llinfos << "Hover" << LLView::sMouseHandlerMessage << llendl;
+ }
+ handled = TRUE;
+ }
+ else if (LLView::sDebugMouseHandling)
+ {
+ if (last_handle_msg != LLStringUtil::null)
+ {
+ last_handle_msg.clear();
+ llinfos << "Hover not handled by view" << llendl;
+ }
+ }
+ }
+
+ if (!handled)
+ {
+ LLTool *tool = LLToolMgr::getInstance()->getCurrentTool();
+
+ if(mMouseInWindow && tool)
+ {
+ handled = tool->handleHover(x, y, mask);
+ }
+ }
+ }
+
+ // Show a new tool tip (or update one that is already shown)
+ BOOL tool_tip_handled = FALSE;
+ std::string tool_tip_msg;
+ if( handled
+ && !mWindow->isCursorHidden())
+ {
+ LLRect screen_sticky_rect = mRootView->getLocalRect();
+ S32 local_x, local_y;
+
+ if (gSavedSettings.getBOOL("DebugShowXUINames"))
+ {
+ LLToolTip::Params params;
+
+ LLView* tooltip_view = mRootView;
+ LLView::tree_iterator_t end_it = mRootView->endTreeDFS();
+ for (LLView::tree_iterator_t it = mRootView->beginTreeDFS(); it != end_it; ++it)
+ {
+ LLView* viewp = *it;
+ LLRect screen_rect;
+ viewp->localRectToScreen(viewp->getLocalRect(), &screen_rect);
+ if (!(viewp->getVisible()
+ && screen_rect.pointInRect(x, y)))
+ {
+ it.skipDescendants();
+ }
+ // only report xui names for LLUICtrls,
+ // and blacklist the various containers we don't care about
+ else if (dynamic_cast<LLUICtrl*>(viewp)
+ && viewp != gMenuHolder
+ && viewp != gFloaterView
+ && viewp != gConsole)
+ {
+ if (dynamic_cast<LLFloater*>(viewp))
+ {
+ // constrain search to descendants of this (frontmost) floater
+ // by resetting iterator
+ it = viewp->beginTreeDFS();
+ }
+
+ // if we are in a new part of the tree (not a descendent of current tooltip_view)
+ // then push the results for tooltip_view and start with a new potential view
+ // NOTE: this emulates visiting only the leaf nodes that meet our criteria
+ if (!viewp->hasAncestor(tooltip_view))
+ {
+ append_xui_tooltip(tooltip_view, params);
+ screen_sticky_rect.intersectWith(tooltip_view->calcScreenRect());
+ }
+ tooltip_view = viewp;
+ }
+ }
+
+ append_xui_tooltip(tooltip_view, params);
+ screen_sticky_rect.intersectWith(tooltip_view->calcScreenRect());
+
+ params.sticky_rect = screen_sticky_rect;
+ params.max_width = 400;
+
+ LLToolTipMgr::instance().show(params);
+ }
+ // if there is a mouse captor, nothing else gets a tooltip
+ else if (mouse_captor)
+ {
+ mouse_captor->screenPointToLocal(x, y, &local_x, &local_y);
+ tool_tip_handled = mouse_captor->handleToolTip(local_x, local_y, mask);
+ }
+ else
+ {
+ // next is top_ctrl
+ if (!tool_tip_handled && top_ctrl)
+ {
+ top_ctrl->screenPointToLocal(x, y, &local_x, &local_y);
+ tool_tip_handled = top_ctrl->handleToolTip(local_x, local_y, mask );
+ }
+
+ if (!tool_tip_handled)
+ {
+ local_x = x; local_y = y;
+ tool_tip_handled = mRootView->handleToolTip(local_x, local_y, mask );
+ }
+
+ LLTool* current_tool = LLToolMgr::getInstance()->getCurrentTool();
+ if (!tool_tip_handled && current_tool)
+ {
+ current_tool->screenPointToLocal(x, y, &local_x, &local_y);
+ tool_tip_handled = current_tool->handleToolTip(local_x, local_y, mask );
+ }
+ }
+ }
+ }
+ else
+ { // just have tools handle hover when UI is turned off
+ LLTool *tool = LLToolMgr::getInstance()->getCurrentTool();
+
+ if(mMouseInWindow && tool)
+ {
+ handled = tool->handleHover(x, y, mask);
+ }
+ }
+
+ updateLayout();
+
+ mLastMousePoint = mCurrentMousePoint;
+
+ // cleanup unused selections when no modal dialogs are open
+ if (LLModalDialog::activeCount() == 0)
+ {
+ LLViewerParcelMgr::getInstance()->deselectUnused();
+ }
+
+ if (LLModalDialog::activeCount() == 0)
+ {
+ LLSelectMgr::getInstance()->deselectUnused();
+ }
+}
+
+
+void LLViewerWindow::updateLayout()
+{
+ LLTool* tool = LLToolMgr::getInstance()->getCurrentTool();
+ if (gFloaterTools != NULL
+ && tool != NULL
+ && tool != gToolNull
+ && tool != LLToolCompInspect::getInstance()
+ && tool != LLToolDragAndDrop::getInstance()
+ && !gSavedSettings.getBOOL("FreezeTime"))
+ {
+ // Suppress the toolbox view if our source tool was the pie tool,
+ // and we've overridden to something else.
+ bool suppress_toolbox =
+ (LLToolMgr::getInstance()->getBaseTool() == LLToolPie::getInstance()) &&
+ (LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance());
+
+ LLMouseHandler *captor = gFocusMgr.getMouseCapture();
+ // With the null, inspect, or drag and drop tool, don't muck
+ // with visibility.
+
+ if (gFloaterTools->isMinimized()
+ || (tool != LLToolPie::getInstance() // not default tool
+ && tool != LLToolCompGun::getInstance() // not coming out of mouselook
+ && !suppress_toolbox // not override in third person
+ && LLToolMgr::getInstance()->getCurrentToolset() != gFaceEditToolset // not special mode
+ && LLToolMgr::getInstance()->getCurrentToolset() != gMouselookToolset
+ && (!captor || dynamic_cast<LLView*>(captor) != NULL))) // not dragging
+ {
+ // Force floater tools to be visible (unless minimized)
+ if (!gFloaterTools->getVisible())
+ {
+ gFloaterTools->openFloater();
+ }
+ // Update the location of the blue box tool popup
+ LLCoordGL select_center_screen;
+ gFloaterTools->updatePopup( select_center_screen, gKeyboard->currentMask(TRUE) );
+ }
+ else
+ {
+ gFloaterTools->setVisible(FALSE);
+ }
+ //gMenuBarView->setItemVisible("BuildTools", gFloaterTools->getVisible());
+ }
+
+ // Always update console
+ if(gConsole)
+ {
+ LLRect console_rect = getChatConsoleRect();
+ gConsole->reshape(console_rect.getWidth(), console_rect.getHeight());
+ gConsole->setRect(console_rect);
+ }
+}
+
+void LLViewerWindow::updateMouseDelta()
+{
+ S32 dx = lltrunc((F32) (mCurrentMousePoint.mX - mLastMousePoint.mX) * LLUI::sGLScaleFactor.mV[VX]);
+ S32 dy = lltrunc((F32) (mCurrentMousePoint.mY - mLastMousePoint.mY) * LLUI::sGLScaleFactor.mV[VY]);
+
+ //RN: fix for asynchronous notification of mouse leaving window not working
+ LLCoordWindow mouse_pos;
+ mWindow->getCursorPosition(&mouse_pos);
+ if (mouse_pos.mX < 0 ||
+ mouse_pos.mY < 0 ||
+ mouse_pos.mX > mWindowRectRaw.getWidth() ||
+ mouse_pos.mY > mWindowRectRaw.getHeight())
+ {
+ mMouseInWindow = FALSE;
+ }
+ else
+ {
+ mMouseInWindow = TRUE;
+ }
+
+ LLVector2 mouse_vel;
+
+ if (gSavedSettings.getBOOL("MouseSmooth"))
+ {
+ static F32 fdx = 0.f;
+ static F32 fdy = 0.f;
+
+ F32 amount = 16.f;
+ fdx = fdx + ((F32) dx - fdx) * llmin(gFrameIntervalSeconds*amount,1.f);
+ fdy = fdy + ((F32) dy - fdy) * llmin(gFrameIntervalSeconds*amount,1.f);
+
+ mCurrentMouseDelta.set(llround(fdx), llround(fdy));
+ mouse_vel.setVec(fdx,fdy);
+ }
+ else
+ {
+ mCurrentMouseDelta.set(dx, dy);
+ mouse_vel.setVec((F32) dx, (F32) dy);
+ }
+
+ mMouseVelocityStat.addValue(mouse_vel.magVec());
+}
+
+void LLViewerWindow::updateKeyboardFocus()
+{
+ if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+ gFocusMgr.setKeyboardFocus(NULL);
+ }
+
+ // clean up current focus
+ LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());
+ if (cur_focus)
+ {
+ if (!cur_focus->isInVisibleChain() || !cur_focus->isInEnabledChain())
+ {
+ // don't release focus, just reassign so that if being given
+ // to a sibling won't call onFocusLost on all the ancestors
+ // gFocusMgr.releaseFocusIfNeeded(cur_focus);
+
+ LLUICtrl* parent = cur_focus->getParentUICtrl();
+ const LLUICtrl* focus_root = cur_focus->findRootMostFocusRoot();
+ bool new_focus_found = false;
+ while(parent)
+ {
+ if (parent->isCtrl()
+ && (parent->hasTabStop() || parent == focus_root)
+ && !parent->getIsChrome()
+ && parent->isInVisibleChain()
+ && parent->isInEnabledChain())
+ {
+ if (!parent->focusFirstItem())
+ {
+ parent->setFocus(TRUE);
+ }
+ new_focus_found = true;
+ break;
+ }
+ parent = parent->getParentUICtrl();
+ }
+
+ // if we didn't find a better place to put focus, just release it
+ // hasFocus() will return true if and only if we didn't touch focus since we
+ // are only moving focus higher in the hierarchy
+ if (!new_focus_found)
+ {
+ cur_focus->setFocus(FALSE);
+ }
+ }
+ else if (cur_focus->isFocusRoot())
+ {
+ // focus roots keep trying to delegate focus to their first valid descendant
+ // this assumes that focus roots are not valid focus holders on their own
+ cur_focus->focusFirstItem();
+ }
+ }
+
+ // last ditch force of edit menu to selection manager
+ if (LLEditMenuHandler::gEditMenuHandler == NULL && LLSelectMgr::getInstance()->getSelection()->getObjectCount())
+ {
+ LLEditMenuHandler::gEditMenuHandler = LLSelectMgr::getInstance();
+ }
+
+ if (gFloaterView->getCycleMode())
+ {
+ // sync all floaters with their focus state
+ gFloaterView->highlightFocusedFloater();
+ gSnapshotFloaterView->highlightFocusedFloater();
+ if ((gKeyboard->currentMask(TRUE) & MASK_CONTROL) == 0)
+ {
+ // control key no longer held down, finish cycle mode
+ gFloaterView->setCycleMode(FALSE);
+
+ gFloaterView->syncFloaterTabOrder();
+ }
+ else
+ {
+ // user holding down CTRL, don't update tab order of floaters
+ }
+ }
+ else
+ {
+ // update focused floater
+ gFloaterView->highlightFocusedFloater();
+ gSnapshotFloaterView->highlightFocusedFloater();
+ // make sure floater visible order is in sync with tab order
+ gFloaterView->syncFloaterTabOrder();
+ }
+
+ if(LLSideTray::instanceCreated())//just getInstance will create sidetray. we don't want this
+ LLSideTray::getInstance()->highlightFocused();
+}
+
+static LLFastTimer::DeclareTimer FTM_UPDATE_WORLD_VIEW("Update World View");
+void LLViewerWindow::updateWorldViewRect(bool use_full_window)
+{
+ LLFastTimer ft(FTM_UPDATE_WORLD_VIEW);
+
+ // start off using whole window to render world
+ LLRect new_world_rect = mWindowRectRaw;
+
+ if (use_full_window == false && mWorldViewPlaceholder.get())
+ {
+ new_world_rect = mWorldViewPlaceholder.get()->calcScreenRect();
+ // clamp to at least a 1x1 rect so we don't try to allocate zero width gl buffers
+ new_world_rect.mTop = llmax(new_world_rect.mTop, new_world_rect.mBottom + 1);
+ new_world_rect.mRight = llmax(new_world_rect.mRight, new_world_rect.mLeft + 1);
+
+ new_world_rect.mLeft = llround((F32)new_world_rect.mLeft * mDisplayScale.mV[VX]);
+ new_world_rect.mRight = llround((F32)new_world_rect.mRight * mDisplayScale.mV[VX]);
+ new_world_rect.mBottom = llround((F32)new_world_rect.mBottom * mDisplayScale.mV[VY]);
+ new_world_rect.mTop = llround((F32)new_world_rect.mTop * mDisplayScale.mV[VY]);
+ }
+
+ if (gSavedSettings.getBOOL("SidebarCameraMovement") == FALSE)
+ {
+ // use right edge of window, ignoring sidebar
+ new_world_rect.mRight = mWindowRectRaw.mRight;
+ }
+
+ if (mWorldViewRectRaw != new_world_rect)
+ {
+ mWorldViewRectRaw = new_world_rect;
+ gResizeScreenTexture = TRUE;
+ LLViewerCamera::getInstance()->setViewHeightInPixels( mWorldViewRectRaw.getHeight() );
+ LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() );
+
+ LLRect old_world_rect_scaled = mWorldViewRectScaled;
+ mWorldViewRectScaled = calcScaledRect(mWorldViewRectRaw, mDisplayScale);
+
+ // sending a signal with a new WorldView rect
+ mOnWorldViewRectUpdated(old_world_rect_scaled, mWorldViewRectScaled);
+ }
+}
+
+void LLViewerWindow::saveLastMouse(const LLCoordGL &point)
+{
+ // Store last mouse location.
+ // If mouse leaves window, pretend last point was on edge of window
+ if (point.mX < 0)
+ {
+ mCurrentMousePoint.mX = 0;
+ }
+ else if (point.mX > getWindowWidthScaled())
+ {
+ mCurrentMousePoint.mX = getWindowWidthScaled();
+ }
+ else
+ {
+ mCurrentMousePoint.mX = point.mX;
+ }
+
+ if (point.mY < 0)
+ {
+ mCurrentMousePoint.mY = 0;
+ }
+ else if (point.mY > getWindowHeightScaled() )
+ {
+ mCurrentMousePoint.mY = getWindowHeightScaled();
+ }
+ else
+ {
+ mCurrentMousePoint.mY = point.mY;
+ }
+}
+
+
+// Draws the selection outlines for the currently selected objects
+// Must be called after displayObjects is called, which sets the mGLName parameter
+// NOTE: This function gets called 3 times:
+// render_ui_3d: FALSE, FALSE, TRUE
+// render_hud_elements: FALSE, FALSE, FALSE
+void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls, BOOL for_hud )
+{
+ LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+
+ if (!for_hud && !for_gl_pick)
+ {
+ // Call this once and only once
+ LLSelectMgr::getInstance()->updateSilhouettes();
+ }
+
+ // Draw fence around land selections
+ if (for_gl_pick)
+ {
+ if (pick_parcel_walls)
+ {
+ LLViewerParcelMgr::getInstance()->renderParcelCollision();
+ }
+ }
+ else if (( for_hud && selection->getSelectType() == SELECT_TYPE_HUD) ||
+ (!for_hud && selection->getSelectType() != SELECT_TYPE_HUD))
+ {
+ LLSelectMgr::getInstance()->renderSilhouettes(for_hud);
+
+ stop_glerror();
+
+ // setup HUD render
+ if (selection->getSelectType() == SELECT_TYPE_HUD && LLSelectMgr::getInstance()->getSelection()->getObjectCount())
+ {
+ LLBBox hud_bbox = gAgentAvatarp->getHUDBBox();
+
+ // set up transform to encompass bounding box of HUD
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ F32 depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f);
+ glOrtho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, depth);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+ glLoadMatrixf(OGL_TO_CFR_ROTATION); // Load Cory's favorite reference frame
+ glTranslatef(-hud_bbox.getCenterLocal().mV[VX] + (depth *0.5f), 0.f, 0.f);
+ }
+
+ // Render light for editing
+ if (LLSelectMgr::sRenderLightRadius && LLToolMgr::getInstance()->inEdit())
+ {
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ LLGLEnable gls_blend(GL_BLEND);
+ LLGLEnable gls_cull(GL_CULL_FACE);
+ LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ if (selection->getSelectType() == SELECT_TYPE_HUD)
+ {
+ F32 zoom = gAgentCamera.mHUDCurZoom;
+ glScalef(zoom, zoom, zoom);
+ }
+
+ struct f : public LLSelectedObjectFunctor
+ {
+ virtual bool apply(LLViewerObject* object)
+ {
+ LLDrawable* drawable = object->mDrawable;
+ if (drawable && drawable->isLight())
+ {
+ LLVOVolume* vovolume = drawable->getVOVolume();
+ glPushMatrix();
+
+ LLVector3 center = drawable->getPositionAgent();
+ glTranslatef(center[0], center[1], center[2]);
+ F32 scale = vovolume->getLightRadius();
+ glScalef(scale, scale, scale);
+
+ LLColor4 color(vovolume->getLightColor(), .5f);
+ glColor4fv(color.mV);
+
+ F32 pixel_area = 100000.f;
+ // Render Outside
+ gSphere.render(pixel_area);
+
+ // Render Inside
+ glCullFace(GL_FRONT);
+ gSphere.render(pixel_area);
+ glCullFace(GL_BACK);
+
+ glPopMatrix();
+ }
+ return true;
+ }
+ } func;
+ LLSelectMgr::getInstance()->getSelection()->applyToObjects(&func);
+
+ glPopMatrix();
+ }
+
+ // NOTE: The average position for the axis arrows of the selected objects should
+ // not be recalculated at this time. If they are, then group rotations will break.
+
+ // Draw arrows at average center of all selected objects
+ LLTool* tool = LLToolMgr::getInstance()->getCurrentTool();
+ if (tool)
+ {
+ if(tool->isAlwaysRendered())
+ {
+ tool->render();
+ }
+ else
+ {
+ if( !LLSelectMgr::getInstance()->getSelection()->isEmpty() )
+ {
+ BOOL moveable_object_selected = FALSE;
+ BOOL all_selected_objects_move = TRUE;
+ BOOL all_selected_objects_modify = TRUE;
+ BOOL selecting_linked_set = !gSavedSettings.getBOOL("EditLinkedParts");
+
+ for (LLObjectSelection::iterator iter = LLSelectMgr::getInstance()->getSelection()->begin();
+ iter != LLSelectMgr::getInstance()->getSelection()->end(); iter++)
+ {
+ LLSelectNode* nodep = *iter;
+ LLViewerObject* object = nodep->getObject();
+ BOOL this_object_movable = FALSE;
+ if (object->permMove() && (object->permModify() || selecting_linked_set))
+ {
+ moveable_object_selected = TRUE;
+ this_object_movable = TRUE;
+ }
+ all_selected_objects_move = all_selected_objects_move && this_object_movable;
+ all_selected_objects_modify = all_selected_objects_modify && object->permModify();
+ }
+
+ BOOL draw_handles = TRUE;
+
+ if (tool == LLToolCompTranslate::getInstance() && (!moveable_object_selected || !all_selected_objects_move))
+ {
+ draw_handles = FALSE;
+ }
+
+ if (tool == LLToolCompRotate::getInstance() && (!moveable_object_selected || !all_selected_objects_move))
+ {
+ draw_handles = FALSE;
+ }
+
+ if ( !all_selected_objects_modify && tool == LLToolCompScale::getInstance() )
+ {
+ draw_handles = FALSE;
+ }
+
+ if( draw_handles )
+ {
+ tool->render();
+ }
+ }
+ }
+ if (selection->getSelectType() == SELECT_TYPE_HUD && selection->getObjectCount())
+ {
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ stop_glerror();
+ }
+ }
+ }
+}
+
+// Return a point near the clicked object representative of the place the object was clicked.
+LLVector3d LLViewerWindow::clickPointInWorldGlobal(S32 x, S32 y_from_bot, LLViewerObject* clicked_object) const
+{
+ // create a normalized vector pointing from the camera center into the
+ // world at the location of the mouse click
+ LLVector3 mouse_direction_global = mouseDirectionGlobal( x, y_from_bot );
+
+ LLVector3d relative_object = clicked_object->getPositionGlobal() - gAgentCamera.getCameraPositionGlobal();
+
+ // make mouse vector as long as object vector, so it touchs a point near
+ // where the user clicked on the object
+ mouse_direction_global *= (F32) relative_object.magVec();
+
+ LLVector3d new_pos;
+ new_pos.setVec(mouse_direction_global);
+ // transform mouse vector back to world coords
+ new_pos += gAgentCamera.getCameraPositionGlobal();
+
+ return new_pos;
+}
+
+
+BOOL LLViewerWindow::clickPointOnSurfaceGlobal(const S32 x, const S32 y, LLViewerObject *objectp, LLVector3d &point_global) const
+{
+ BOOL intersect = FALSE;
+
+// U8 shape = objectp->mPrimitiveCode & LL_PCODE_BASE_MASK;
+ if (!intersect)
+ {
+ point_global = clickPointInWorldGlobal(x, y, objectp);
+ llinfos << "approx intersection at " << (objectp->getPositionGlobal() - point_global) << llendl;
+ }
+ else
+ {
+ llinfos << "good intersection at " << (objectp->getPositionGlobal() - point_global) << llendl;
+ }
+
+ return intersect;
+}
+
+void LLViewerWindow::pickAsync(S32 x, S32 y_from_bot, MASK mask, void (*callback)(const LLPickInfo& info), BOOL pick_transparent)
+{
+ if (gNoRender)
+ {
+ return;
+ }
+
+ BOOL in_build_mode = LLFloaterReg::instanceVisible("build");
+ if (in_build_mode || LLDrawPoolAlpha::sShowDebugAlpha)
+ {
+ // build mode allows interaction with all transparent objects
+ // "Show Debug Alpha" means no object actually transparent
+ pick_transparent = TRUE;
+ }
+
+ LLPickInfo pick_info(LLCoordGL(x, y_from_bot), mask, pick_transparent, TRUE, callback);
+ schedulePick(pick_info);
+}
+
+void LLViewerWindow::schedulePick(LLPickInfo& pick_info)
+{
+ if (mPicks.size() >= 1024 || mWindow->getMinimized())
+ { //something went wrong, picks are being scheduled but not processed
+
+ if (pick_info.mPickCallback)
+ {
+ pick_info.mPickCallback(pick_info);
+ }
+
+ return;
+ }
+ mPicks.push_back(pick_info);
+
+ // delay further event processing until we receive results of pick
+ // only do this for async picks so that handleMouseUp won't be called
+ // until the pick triggered in handleMouseDown has been processed, for example
+ mWindow->delayInputProcessing();
+}
+
+
+void LLViewerWindow::performPick()
+{
+ if (gNoRender)
+ {
+ return;
+ }
+
+ if (!mPicks.empty())
+ {
+ std::vector<LLPickInfo>::iterator pick_it;
+ for (pick_it = mPicks.begin(); pick_it != mPicks.end(); ++pick_it)
+ {
+ pick_it->fetchResults();
+ }
+
+ mLastPick = mPicks.back();
+ mPicks.clear();
+ }
+}
+
+void LLViewerWindow::returnEmptyPicks()
+{
+ std::vector<LLPickInfo>::iterator pick_it;
+ for (pick_it = mPicks.begin(); pick_it != mPicks.end(); ++pick_it)
+ {
+ mLastPick = *pick_it;
+ // just trigger callback with empty results
+ if (pick_it->mPickCallback)
+ {
+ pick_it->mPickCallback(*pick_it);
+ }
+ }
+ mPicks.clear();
+}
+
+// Performs the GL object/land pick.
+LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, BOOL pick_transparent)
+{
+ if (gNoRender)
+ {
+ return LLPickInfo();
+ }
+
+ BOOL in_build_mode = LLFloaterReg::instanceVisible("build");
+ if (in_build_mode || LLDrawPoolAlpha::sShowDebugAlpha)
+ {
+ // build mode allows interaction with all transparent objects
+ // "Show Debug Alpha" means no object actually transparent
+ pick_transparent = TRUE;
+ }
+
+ // shortcut queueing in mPicks and just update mLastPick in place
+ mLastPick = LLPickInfo(LLCoordGL(x, y_from_bot), gKeyboard->currentMask(TRUE), pick_transparent, TRUE, NULL);
+ mLastPick.fetchResults();
+
+ return mLastPick;
+}
+
+LLHUDIcon* LLViewerWindow::cursorIntersectIcon(S32 mouse_x, S32 mouse_y, F32 depth,
+ LLVector3* intersection)
+{
+ S32 x = mouse_x;
+ S32 y = mouse_y;
+
+ if ((mouse_x == -1) && (mouse_y == -1)) // use current mouse position
+ {
+ x = getCurrentMouseX();
+ y = getCurrentMouseY();
+ }
+
+ // world coordinates of mouse
+ LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y);
+ LLVector3 mouse_point_global = LLViewerCamera::getInstance()->getOrigin();
+ LLVector3 mouse_world_start = mouse_point_global;
+ LLVector3 mouse_world_end = mouse_point_global + mouse_direction_global * depth;
+
+ return LLHUDIcon::lineSegmentIntersectAll(mouse_world_start, mouse_world_end, intersection);
+
+
+}
+
+LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 depth,
+ LLViewerObject *this_object,
+ S32 this_face,
+ BOOL pick_transparent,
+ S32* face_hit,
+ LLVector3 *intersection,
+ LLVector2 *uv,
+ LLVector3 *normal,
+ LLVector3 *binormal)
+{
+ S32 x = mouse_x;
+ S32 y = mouse_y;
+
+ if ((mouse_x == -1) && (mouse_y == -1)) // use current mouse position
+ {
+ x = getCurrentMouseX();
+ y = getCurrentMouseY();
+ }
+
+ // HUD coordinates of mouse
+ LLVector3 mouse_point_hud = mousePointHUD(x, y);
+ LLVector3 mouse_hud_start = mouse_point_hud - LLVector3(depth, 0, 0);
+ LLVector3 mouse_hud_end = mouse_point_hud + LLVector3(depth, 0, 0);
+
+ // world coordinates of mouse
+ LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y);
+ LLVector3 mouse_point_global = LLViewerCamera::getInstance()->getOrigin();
+
+ //get near clip plane
+ LLVector3 n = LLViewerCamera::getInstance()->getAtAxis();
+ LLVector3 p = mouse_point_global + n * LLViewerCamera::getInstance()->getNear();
+
+ //project mouse point onto plane
+ LLVector3 pos;
+ line_plane(mouse_point_global, mouse_direction_global, p, n, pos);
+ mouse_point_global = pos;
+
+ LLVector3 mouse_world_start = mouse_point_global;
+ LLVector3 mouse_world_end = mouse_point_global + mouse_direction_global * depth;
+
+
+ LLViewerObject* found = NULL;
+
+ if (this_object) // check only this object
+ {
+ if (this_object->isHUDAttachment()) // is a HUD object?
+ {
+ if (this_object->lineSegmentIntersect(mouse_hud_start, mouse_hud_end, this_face, pick_transparent,
+ face_hit, intersection, uv, normal, binormal))
+ {
+ found = this_object;
+ }
+ }
+
+ else // is a world object
+ {
+ if (this_object->lineSegmentIntersect(mouse_world_start, mouse_world_end, this_face, pick_transparent,
+ face_hit, intersection, uv, normal, binormal))
+ {
+ found = this_object;
+ }
+ }
+ }
+
+ else // check ALL objects
+ {
+ found = gPipeline.lineSegmentIntersectInHUD(mouse_hud_start, mouse_hud_end, pick_transparent,
+ face_hit, intersection, uv, normal, binormal);
+
+ if (!found) // if not found in HUD, look in world:
+
+ {
+ found = gPipeline.lineSegmentIntersectInWorld(mouse_world_start, mouse_world_end, pick_transparent,
+ face_hit, intersection, uv, normal, binormal);
+ }
+
+ }
+
+ return found;
+}
+
+// Returns unit vector relative to camera
+// indicating direction of point on screen x,y
+LLVector3 LLViewerWindow::mouseDirectionGlobal(const S32 x, const S32 y) const
+{
+ // find vertical field of view
+ F32 fov = LLViewerCamera::getInstance()->getView();
+
+ // find world view center in scaled ui coordinates
+ F32 center_x = getWorldViewRectScaled().getCenterX();
+ F32 center_y = getWorldViewRectScaled().getCenterY();
+
+ // calculate pixel distance to screen
+ F32 distance = ((F32)getWorldViewHeightScaled() * 0.5f) / (tan(fov / 2.f));
+
+ // calculate click point relative to middle of screen
+ F32 click_x = x - center_x;
+ F32 click_y = y - center_y;
+
+ // compute mouse vector
+ LLVector3 mouse_vector = distance * LLViewerCamera::getInstance()->getAtAxis()
+ - click_x * LLViewerCamera::getInstance()->getLeftAxis()
+ + click_y * LLViewerCamera::getInstance()->getUpAxis();
+
+ mouse_vector.normVec();
+
+ return mouse_vector;
+}
+
+LLVector3 LLViewerWindow::mousePointHUD(const S32 x, const S32 y) const
+{
+ // find screen resolution
+ S32 height = getWorldViewHeightScaled();
+
+ // find world view center
+ F32 center_x = getWorldViewRectScaled().getCenterX();
+ F32 center_y = getWorldViewRectScaled().getCenterY();
+
+ // remap with uniform scale (1/height) so that top is -0.5, bottom is +0.5
+ F32 hud_x = -((F32)x - center_x) / height;
+ F32 hud_y = ((F32)y - center_y) / height;
+
+ return LLVector3(0.f, hud_x/gAgentCamera.mHUDCurZoom, hud_y/gAgentCamera.mHUDCurZoom);
+}
+
+// Returns unit vector relative to camera in camera space
+// indicating direction of point on screen x,y
+LLVector3 LLViewerWindow::mouseDirectionCamera(const S32 x, const S32 y) const
+{
+ // find vertical field of view
+ F32 fov_height = LLViewerCamera::getInstance()->getView();
+ F32 fov_width = fov_height * LLViewerCamera::getInstance()->getAspect();
+
+ // find screen resolution
+ S32 height = getWorldViewHeightScaled();
+ S32 width = getWorldViewWidthScaled();
+
+ // find world view center
+ F32 center_x = getWorldViewRectScaled().getCenterX();
+ F32 center_y = getWorldViewRectScaled().getCenterY();
+
+ // calculate click point relative to middle of screen
+ F32 click_x = (((F32)x - center_x) / (F32)width) * fov_width * -1.f;
+ F32 click_y = (((F32)y - center_y) / (F32)height) * fov_height;
+
+ // compute mouse vector
+ LLVector3 mouse_vector = LLVector3(0.f, 0.f, -1.f);
+ LLQuaternion mouse_rotate;
+ mouse_rotate.setQuat(click_y, click_x, 0.f);
+
+ mouse_vector = mouse_vector * mouse_rotate;
+ // project to z = -1 plane;
+ mouse_vector = mouse_vector * (-1.f / mouse_vector.mV[VZ]);
+
+ return mouse_vector;
+}
+
+
+
+BOOL LLViewerWindow::mousePointOnPlaneGlobal(LLVector3d& point, const S32 x, const S32 y,
+ const LLVector3d &plane_point_global,
+ const LLVector3 &plane_normal_global)
+{
+ LLVector3d mouse_direction_global_d;
+
+ mouse_direction_global_d.setVec(mouseDirectionGlobal(x,y));
+ LLVector3d plane_normal_global_d;
+ plane_normal_global_d.setVec(plane_normal_global);
+ F64 plane_mouse_dot = (plane_normal_global_d * mouse_direction_global_d);
+ LLVector3d plane_origin_camera_rel = plane_point_global - gAgentCamera.getCameraPositionGlobal();
+ F64 mouse_look_at_scale = (plane_normal_global_d * plane_origin_camera_rel)
+ / plane_mouse_dot;
+ if (llabs(plane_mouse_dot) < 0.00001)
+ {
+ // if mouse is parallel to plane, return closest point on line through plane origin
+ // that is parallel to camera plane by scaling mouse direction vector
+ // by distance to plane origin, modulated by deviation of mouse direction from plane origin
+ LLVector3d plane_origin_dir = plane_origin_camera_rel;
+ plane_origin_dir.normVec();
+
+ mouse_look_at_scale = plane_origin_camera_rel.magVec() / (plane_origin_dir * mouse_direction_global_d);
+ }
+
+ point = gAgentCamera.getCameraPositionGlobal() + mouse_look_at_scale * mouse_direction_global_d;
+
+ return mouse_look_at_scale > 0.0;
+}
+
+
+// Returns global position
+BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d *land_position_global)
+{
+ LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y);
+ F32 mouse_dir_scale;
+ BOOL hit_land = FALSE;
+ LLViewerRegion *regionp;
+ F32 land_z;
+ const F32 FIRST_PASS_STEP = 1.0f; // meters
+ const F32 SECOND_PASS_STEP = 0.1f; // meters
+ LLVector3d camera_pos_global;
+
+ camera_pos_global = gAgentCamera.getCameraPositionGlobal();
+ LLVector3d probe_point_global;
+ LLVector3 probe_point_region;
+
+ // walk forwards to find the point
+ for (mouse_dir_scale = FIRST_PASS_STEP; mouse_dir_scale < gAgentCamera.mDrawDistance; mouse_dir_scale += FIRST_PASS_STEP)
+ {
+ LLVector3d mouse_direction_global_d;
+ mouse_direction_global_d.setVec(mouse_direction_global * mouse_dir_scale);
+ probe_point_global = camera_pos_global + mouse_direction_global_d;
+
+ regionp = LLWorld::getInstance()->resolveRegionGlobal(probe_point_region, probe_point_global);
+
+ if (!regionp)
+ {
+ // ...we're outside the world somehow
+ continue;
+ }
+
+ S32 i = (S32) (probe_point_region.mV[VX]/regionp->getLand().getMetersPerGrid());
+ S32 j = (S32) (probe_point_region.mV[VY]/regionp->getLand().getMetersPerGrid());
+ S32 grids_per_edge = (S32) regionp->getLand().mGridsPerEdge;
+ if ((i >= grids_per_edge) || (j >= grids_per_edge))
+ {
+ //llinfos << "LLViewerWindow::mousePointOnLand probe_point is out of region" << llendl;
+ continue;
+ }
+
+ land_z = regionp->getLand().resolveHeightRegion(probe_point_region);
+
+ //llinfos << "mousePointOnLand initial z " << land_z << llendl;
+
+ if (probe_point_region.mV[VZ] < land_z)
+ {
+ // ...just went under land
+
+ // cout << "under land at " << probe_point << " scale " << mouse_vec_scale << endl;
+
+ hit_land = TRUE;
+ break;
+ }
+ }
+
+
+ if (hit_land)
+ {
+ // Don't go more than one step beyond where we stopped above.
+ // This can't just be "mouse_vec_scale" because floating point error
+ // will stop the loop before the last increment.... X - 1.0 + 0.1 + 0.1 + ... + 0.1 != X
+ F32 stop_mouse_dir_scale = mouse_dir_scale + FIRST_PASS_STEP;
+
+ // take a step backwards, then walk forwards again to refine position
+ for ( mouse_dir_scale -= FIRST_PASS_STEP; mouse_dir_scale <= stop_mouse_dir_scale; mouse_dir_scale += SECOND_PASS_STEP)
+ {
+ LLVector3d mouse_direction_global_d;
+ mouse_direction_global_d.setVec(mouse_direction_global * mouse_dir_scale);
+ probe_point_global = camera_pos_global + mouse_direction_global_d;
+
+ regionp = LLWorld::getInstance()->resolveRegionGlobal(probe_point_region, probe_point_global);
+
+ if (!regionp)
+ {
+ // ...we're outside the world somehow
+ continue;
+ }
+
+ /*
+ i = (S32) (local_probe_point.mV[VX]/regionp->getLand().getMetersPerGrid());
+ j = (S32) (local_probe_point.mV[VY]/regionp->getLand().getMetersPerGrid());
+ if ((i >= regionp->getLand().mGridsPerEdge) || (j >= regionp->getLand().mGridsPerEdge))
+ {
+ // llinfos << "LLViewerWindow::mousePointOnLand probe_point is out of region" << llendl;
+ continue;
+ }
+ land_z = regionp->getLand().mSurfaceZ[ i + j * (regionp->getLand().mGridsPerEdge) ];
+ */
+
+ land_z = regionp->getLand().resolveHeightRegion(probe_point_region);
+
+ //llinfos << "mousePointOnLand refine z " << land_z << llendl;
+
+ if (probe_point_region.mV[VZ] < land_z)
+ {
+ // ...just went under land again
+
+ *land_position_global = probe_point_global;
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+// Saves an image to the harddrive as "SnapshotX" where X >= 1.
+BOOL LLViewerWindow::saveImageNumbered(LLImageFormatted *image)
+{
+ if (!image)
+ {
+ return FALSE;
+ }
+
+ LLFilePicker::ESaveFilter pick_type;
+ std::string extension("." + image->getExtension());
+ if (extension == ".j2c")
+ pick_type = LLFilePicker::FFSAVE_J2C;
+ else if (extension == ".bmp")
+ pick_type = LLFilePicker::FFSAVE_BMP;
+ else if (extension == ".jpg")
+ pick_type = LLFilePicker::FFSAVE_JPEG;
+ else if (extension == ".png")
+ pick_type = LLFilePicker::FFSAVE_PNG;
+ else if (extension == ".tga")
+ pick_type = LLFilePicker::FFSAVE_TGA;
+ else
+ pick_type = LLFilePicker::FFSAVE_ALL; // ???
+
+ // Get a base file location if needed.
+ if ( ! isSnapshotLocSet())
+ {
+ std::string proposed_name( sSnapshotBaseName );
+
+ // getSaveFile will append an appropriate extension to the proposed name, based on the ESaveFilter constant passed in.
+
+ // pick a directory in which to save
+ LLFilePicker& picker = LLFilePicker::instance();
+ if (!picker.getSaveFile(pick_type, proposed_name))
+ {
+ // Clicked cancel
+ return FALSE;
+ }
+
+ // Copy the directory + file name
+ std::string filepath = picker.getFirstFile();
+
+ LLViewerWindow::sSnapshotBaseName = gDirUtilp->getBaseFileName(filepath, true);
+ LLViewerWindow::sSnapshotDir = gDirUtilp->getDirName(filepath);
+ }
+
+ // Look for an unused file name
+ std::string filepath;
+ S32 i = 1;
+ S32 err = 0;
+
+ do
+ {
+ filepath = sSnapshotDir;
+ filepath += gDirUtilp->getDirDelimiter();
+ filepath += sSnapshotBaseName;
+ filepath += llformat("_%.3d",i);
+ filepath += extension;
+
+ llstat stat_info;
+ err = LLFile::stat( filepath, &stat_info );
+ i++;
+ }
+ while( -1 != err ); // search until the file is not found (i.e., stat() gives an error).
+
+ return image->save(filepath);
+}
+
+void LLViewerWindow::resetSnapshotLoc()
+{
+ sSnapshotDir.clear();
+}
+
+static S32 BORDERHEIGHT = 0;
+static S32 BORDERWIDTH = 0;
+
+// static
+void LLViewerWindow::movieSize(S32 new_width, S32 new_height)
+{
+ LLCoordScreen size;
+ gViewerWindow->mWindow->getSize(&size);
+ if ( (size.mX != new_width + BORDERWIDTH)
+ ||(size.mY != new_height + BORDERHEIGHT))
+ {
+ // use actual display dimensions, not virtual UI dimensions
+ S32 x = gViewerWindow->getWindowWidthRaw();
+ S32 y = gViewerWindow->getWindowHeightRaw();
+ BORDERWIDTH = size.mX - x;
+ BORDERHEIGHT = size.mY- y;
+ LLCoordScreen new_size(new_width + BORDERWIDTH,
+ new_height + BORDERHEIGHT);
+ gViewerWindow->mWindow->setSize(new_size);
+ }
+}
+
+BOOL LLViewerWindow::saveSnapshot( const std::string& filepath, S32 image_width, S32 image_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type)
+{
+ llinfos << "Saving snapshot to: " << filepath << llendl;
+
+ LLPointer<LLImageRaw> raw = new LLImageRaw;
+ BOOL success = rawSnapshot(raw, image_width, image_height, TRUE, FALSE, show_ui, do_rebuild);
+
+ if (success)
+ {
+ LLPointer<LLImageBMP> bmp_image = new LLImageBMP;
+ success = bmp_image->encode(raw, 0.0f);
+ if( success )
+ {
+ success = bmp_image->save(filepath);
+ }
+ else
+ {
+ llwarns << "Unable to encode bmp snapshot" << llendl;
+ }
+ }
+ else
+ {
+ llwarns << "Unable to capture raw snapshot" << llendl;
+ }
+
+ return success;
+}
+
+
+void LLViewerWindow::playSnapshotAnimAndSound()
+{
+ if (gSavedSettings.getBOOL("QuietSnapshotsToDisk"))
+ {
+ return;
+ }
+ gAgent.sendAnimationRequest(ANIM_AGENT_SNAPSHOT, ANIM_REQUEST_START);
+ send_sound_trigger(LLUUID(gSavedSettings.getString("UISndSnapshot")), 1.0f);
+}
+
+BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type)
+{
+ return rawSnapshot(raw, preview_width, preview_height, FALSE, FALSE, show_ui, do_rebuild, type);
+}
+
+// Saves the image from the screen to the specified filename and path.
+BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height,
+ BOOL keep_window_aspect, BOOL is_texture, BOOL show_ui, BOOL do_rebuild, ESnapshotType type, S32 max_size)
+{
+ if (!raw)
+ {
+ return FALSE;
+ }
+
+ // PRE SNAPSHOT
+ gDisplaySwapBuffers = FALSE;
+
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ setCursor(UI_CURSOR_WAIT);
+
+ // Hide all the UI widgets first and draw a frame
+ BOOL prev_draw_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI) ? TRUE : FALSE;
+
+ show_ui = show_ui ? TRUE : FALSE;
+
+ if ( prev_draw_ui != show_ui)
+ {
+ LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI);
+ }
+
+ BOOL hide_hud = !gSavedSettings.getBOOL("RenderHUDInSnapshot") && LLPipeline::sShowHUDAttachments;
+ if (hide_hud)
+ {
+ LLPipeline::sShowHUDAttachments = FALSE;
+ }
+
+ // if not showing ui, use full window to render world view
+ updateWorldViewRect(!show_ui);
+
+ // Copy screen to a buffer
+ // crop sides or top and bottom, if taking a snapshot of different aspect ratio
+ // from window
+ LLRect window_rect = show_ui ? getWindowRectRaw() : getWorldViewRectRaw();
+
+ S32 snapshot_width = window_rect.getWidth();
+ S32 snapshot_height = window_rect.getHeight();
+ // SNAPSHOT
+ S32 window_width = snapshot_width;
+ S32 window_height = snapshot_height;
+
+ if (show_ui)
+ {
+ image_width = llmin(image_width, window_width);
+ image_height = llmin(image_height, window_height);
+ }
+
+ F32 scale_factor = 1.0f ;
+ if(!keep_window_aspect) //image cropping
+ {
+ F32 ratio = llmin( (F32)window_width / image_width , (F32)window_height / image_height) ;
+ snapshot_width = (S32)(ratio * image_width) ;
+ snapshot_height = (S32)(ratio * image_height) ;
+ scale_factor = llmax(1.0f, 1.0f / ratio) ;
+ }
+ else //the scene(window) proportion needs to be maintained.
+ {
+ if(image_width > window_width || image_height > window_height) //need to enlarge the scene
+ {
+ F32 ratio = llmin( (F32)window_width / image_width , (F32)window_height / image_height) ;
+ snapshot_width = (S32)(ratio * image_width) ;
+ snapshot_height = (S32)(ratio * image_height) ;
+ scale_factor = llmax(1.0f, 1.0f / ratio) ;
+ }
+ }
+
+ if (show_ui && scale_factor > 1.f)
+ {
+ llwarns << "over scaling UI not supported." << llendl;
+ }
+
+ S32 buffer_x_offset = llfloor(((window_width - snapshot_width) * scale_factor) / 2.f);
+ S32 buffer_y_offset = llfloor(((window_height - snapshot_height) * scale_factor) / 2.f);
+
+ S32 image_buffer_x = llfloor(snapshot_width*scale_factor) ;
+ S32 image_buffer_y = llfloor(snapshot_height *scale_factor) ;
+
+ if(image_buffer_x > max_size || image_buffer_y > max_size) //boundary check to avoid memory overflow
+ {
+ scale_factor *= llmin((F32)max_size / image_buffer_x, (F32)max_size / image_buffer_y) ;
+ image_buffer_x = llfloor(snapshot_width*scale_factor) ;
+ image_buffer_y = llfloor(snapshot_height *scale_factor) ;
+ }
+ if(image_buffer_x > 0 && image_buffer_y > 0)
+ {
+ raw->resize(image_buffer_x, image_buffer_y, 3);
+ }
+ else
+ {
+ return FALSE ;
+ }
+ if(raw->isBufferInvalid())
+ {
+ return FALSE ;
+ }
+
+ BOOL high_res = scale_factor >= 2.f; // Font scaling is slow, only do so if rez is much higher
+ if (high_res && show_ui)
+ {
+ llwarns << "High res UI snapshot not supported. " << llendl;
+ /*send_agent_pause();
+ //rescale fonts
+ initFonts(scale_factor);
+ LLHUDObject::reshapeAll();*/
+ }
+
+ S32 output_buffer_offset_y = 0;
+
+ F32 depth_conversion_factor_1 = (LLViewerCamera::getInstance()->getFar() + LLViewerCamera::getInstance()->getNear()) / (2.f * LLViewerCamera::getInstance()->getFar() * LLViewerCamera::getInstance()->getNear());
+ F32 depth_conversion_factor_2 = (LLViewerCamera::getInstance()->getFar() - LLViewerCamera::getInstance()->getNear()) / (2.f * LLViewerCamera::getInstance()->getFar() * LLViewerCamera::getInstance()->getNear());
+
+ gObjectList.generatePickList(*LLViewerCamera::getInstance());
+
+ for (int subimage_y = 0; subimage_y < scale_factor; ++subimage_y)
+ {
+ S32 subimage_y_offset = llclamp(buffer_y_offset - (subimage_y * window_height), 0, window_height);;
+ // handle fractional columns
+ U32 read_height = llmax(0, (window_height - subimage_y_offset) -
+ llmax(0, (window_height * (subimage_y + 1)) - (buffer_y_offset + raw->getHeight())));
+
+ S32 output_buffer_offset_x = 0;
+ for (int subimage_x = 0; subimage_x < scale_factor; ++subimage_x)
+ {
+ gDisplaySwapBuffers = FALSE;
+ gDepthDirty = TRUE;
+
+ const U32 subfield = subimage_x+(subimage_y*llceil(scale_factor));
+
+ if (LLPipeline::sRenderDeferred)
+ {
+ display(do_rebuild, scale_factor, subfield, TRUE);
+ }
+ else
+ {
+ display(do_rebuild, scale_factor, subfield, TRUE);
+ // Required for showing the GUI in snapshots and performing bloom composite overlay
+ // Call even if show_ui is FALSE
+ render_ui(scale_factor, subfield);
+ }
+
+ S32 subimage_x_offset = llclamp(buffer_x_offset - (subimage_x * window_width), 0, window_width);
+ // handle fractional rows
+ U32 read_width = llmax(0, (window_width - subimage_x_offset) -
+ llmax(0, (window_width * (subimage_x + 1)) - (buffer_x_offset + raw->getWidth())));
+ for(U32 out_y = 0; out_y < read_height ; out_y++)
+ {
+ S32 output_buffer_offset = (
+ (out_y * (raw->getWidth())) // ...plus iterated y...
+ + (window_width * subimage_x) // ...plus subimage start in x...
+ + (raw->getWidth() * window_height * subimage_y) // ...plus subimage start in y...
+ - output_buffer_offset_x // ...minus buffer padding x...
+ - (output_buffer_offset_y * (raw->getWidth())) // ...minus buffer padding y...
+ ) * raw->getComponents();
+
+ // Ping the wathdog thread every 100 lines to keep us alive (arbitrary number, feel free to change)
+ if (out_y % 100 == 0)
+ {
+ LLAppViewer::instance()->pingMainloopTimeout("LLViewerWindow::rawSnapshot");
+ }
+
+ if (type == SNAPSHOT_TYPE_COLOR)
+ {
+ glReadPixels(
+ subimage_x_offset, out_y + subimage_y_offset,
+ read_width, 1,
+ GL_RGB, GL_UNSIGNED_BYTE,
+ raw->getData() + output_buffer_offset
+ );
+ }
+ else // SNAPSHOT_TYPE_DEPTH
+ {
+ LLPointer<LLImageRaw> depth_line_buffer = new LLImageRaw(read_width, 1, sizeof(GL_FLOAT)); // need to store floating point values
+ glReadPixels(
+ subimage_x_offset, out_y + subimage_y_offset,
+ read_width, 1,
+ GL_DEPTH_COMPONENT, GL_FLOAT,
+ depth_line_buffer->getData()// current output pixel is beginning of buffer...
+ );
+
+ for (S32 i = 0; i < (S32)read_width; i++)
+ {
+ F32 depth_float = *(F32*)(depth_line_buffer->getData() + (i * sizeof(F32)));
+
+ F32 linear_depth_float = 1.f / (depth_conversion_factor_1 - (depth_float * depth_conversion_factor_2));
+ U8 depth_byte = F32_to_U8(linear_depth_float, LLViewerCamera::getInstance()->getNear(), LLViewerCamera::getInstance()->getFar());
+ //write converted scanline out to result image
+ for(S32 j = 0; j < raw->getComponents(); j++)
+ {
+ *(raw->getData() + output_buffer_offset + (i * raw->getComponents()) + j) = depth_byte;
+ }
+ }
+ }
+ }
+ output_buffer_offset_x += subimage_x_offset;
+ stop_glerror();
+ }
+ output_buffer_offset_y += subimage_y_offset;
+ }
+
+ gDisplaySwapBuffers = FALSE;
+ gDepthDirty = TRUE;
+
+ // POST SNAPSHOT
+ if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+ LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI);
+ }
+
+ if (hide_hud)
+ {
+ LLPipeline::sShowHUDAttachments = TRUE;
+ }
+
+ /*if (high_res)
+ {
+ initFonts(1.f);
+ LLHUDObject::reshapeAll();
+ }*/
+
+ // Pre-pad image to number of pixels such that the line length is a multiple of 4 bytes (for BMP encoding)
+ // Note: this formula depends on the number of components being 3. Not obvious, but it's correct.
+ image_width += (image_width * 3) % 4;
+
+ BOOL ret = TRUE ;
+ // Resize image
+ if(llabs(image_width - image_buffer_x) > 4 || llabs(image_height - image_buffer_y) > 4)
+ {
+ ret = raw->scale( image_width, image_height );
+ }
+ else if(image_width != image_buffer_x || image_height != image_buffer_y)
+ {
+ ret = raw->scale( image_width, image_height, FALSE );
+ }
+
+
+ setCursor(UI_CURSOR_ARROW);
+
+ if (do_rebuild)
+ {
+ // If we had to do a rebuild, that means that the lists of drawables to be rendered
+ // was empty before we started.
+ // Need to reset these, otherwise we call state sort on it again when render gets called the next time
+ // and we stand a good chance of crashing on rebuild because the render drawable arrays have multiple copies of
+ // objects on them.
+ gPipeline.resetDrawOrders();
+ }
+
+ if (high_res)
+ {
+ send_agent_resume();
+ }
+
+ return ret;
+}
+
+void LLViewerWindow::destroyWindow()
+{
+ if (mWindow)
+ {
+ LLWindowManager::destroyWindow(mWindow);
+ }
+ mWindow = NULL;
+}
+
+
+void LLViewerWindow::drawMouselookInstructions()
+{
+ // Draw instructions for mouselook ("Press ESC to return to World View" partially transparent at the bottom of the screen.)
+ const std::string instructions = LLTrans::getString("LeaveMouselook");
+ const LLFontGL* font = LLFontGL::getFont(LLFontDescriptor("SansSerif", "Large", LLFontGL::BOLD));
+
+ //to be on top of Bottom bar when it is opened
+ const S32 INSTRUCTIONS_PAD = 50;
+
+ font->renderUTF8(
+ instructions, 0,
+ getWorldViewRectScaled().getCenterX(),
+ getWorldViewRectScaled().mBottom + INSTRUCTIONS_PAD,
+ LLColor4( 1.0f, 1.0f, 1.0f, 0.5f ),
+ LLFontGL::HCENTER, LLFontGL::TOP,
+ LLFontGL::NORMAL,LLFontGL::DROP_SHADOW);
+}
+
+void* LLViewerWindow::getPlatformWindow() const
+{
+ return mWindow->getPlatformWindow();
+}
+
+void* LLViewerWindow::getMediaWindow() const
+{
+ return mWindow->getMediaWindow();
+}
+
+void LLViewerWindow::focusClient() const
+{
+ return mWindow->focusClient();
+}
+
+LLRootView* LLViewerWindow::getRootView() const
+{
+ return mRootView;
+}
+
+LLRect LLViewerWindow::getWorldViewRectScaled() const
+{
+ return mWorldViewRectScaled;
+}
+
+S32 LLViewerWindow::getWorldViewHeightScaled() const
+{
+ return mWorldViewRectScaled.getHeight();
+}
+
+S32 LLViewerWindow::getWorldViewWidthScaled() const
+{
+ return mWorldViewRectScaled.getWidth();
+}
+
+
+S32 LLViewerWindow::getWorldViewHeightRaw() const
+{
+ return mWorldViewRectRaw.getHeight();
+}
+
+S32 LLViewerWindow::getWorldViewWidthRaw() const
+{
+ return mWorldViewRectRaw.getWidth();
+}
+
+S32 LLViewerWindow::getWindowHeightScaled() const
+{
+ return mWindowRectScaled.getHeight();
+}
+
+S32 LLViewerWindow::getWindowWidthScaled() const
+{
+ return mWindowRectScaled.getWidth();
+}
+
+S32 LLViewerWindow::getWindowHeightRaw() const
+{
+ return mWindowRectRaw.getHeight();
+}
+
+S32 LLViewerWindow::getWindowWidthRaw() const
+{
+ return mWindowRectRaw.getWidth();
+}
+
+void LLViewerWindow::setup2DRender()
+{
+ // setup ortho camera
+ gl_state_for_2d(mWindowRectRaw.getWidth(), mWindowRectRaw.getHeight());
+ setup2DViewport();
+}
+
+void LLViewerWindow::setup2DViewport(S32 x_offset, S32 y_offset)
+{
+ gGLViewport[0] = mWindowRectRaw.mLeft + x_offset;
+ gGLViewport[1] = mWindowRectRaw.mBottom + y_offset;
+ gGLViewport[2] = mWindowRectRaw.getWidth();
+ gGLViewport[3] = mWindowRectRaw.getHeight();
+ glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
+}
+
+
+void LLViewerWindow::setup3DRender()
+{
+ // setup perspective camera
+ LLViewerCamera::getInstance()->setPerspective(NOT_FOR_SELECTION, mWorldViewRectRaw.mLeft, mWorldViewRectRaw.mBottom, mWorldViewRectRaw.getWidth(), mWorldViewRectRaw.getHeight(), FALSE, LLViewerCamera::getInstance()->getNear(), MAX_FAR_CLIP*2.f);
+ setup3DViewport();
+}
+
+void LLViewerWindow::setup3DViewport(S32 x_offset, S32 y_offset)
+{
+ gGLViewport[0] = mWorldViewRectRaw.mLeft + x_offset;
+ gGLViewport[1] = mWorldViewRectRaw.mBottom + y_offset;
+ gGLViewport[2] = mWorldViewRectRaw.getWidth();
+ gGLViewport[3] = mWorldViewRectRaw.getHeight();
+ glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
+}
+
+void LLViewerWindow::setShowProgress(const BOOL show)
+{
+ if (mProgressView)
+ {
+ mProgressView->setVisible(show);
+ }
+}
+
+BOOL LLViewerWindow::getShowProgress() const
+{
+ return (mProgressView && mProgressView->getVisible());
+}
+
+void LLViewerWindow::setProgressString(const std::string& string)
+{
+ if (mProgressView)
+ {
+ mProgressView->setText(string);
+ }
+}
+
+void LLViewerWindow::setProgressMessage(const std::string& msg)
+{
+ if(mProgressView)
+ {
+ mProgressView->setMessage(msg);
+ }
+}
+
+void LLViewerWindow::setProgressPercent(const F32 percent)
+{
+ if (mProgressView)
+ {
+ mProgressView->setPercent(percent);
+ }
+}
+
+void LLViewerWindow::setProgressCancelButtonVisible( BOOL b, const std::string& label )
+{
+ if (mProgressView)
+ {
+ mProgressView->setCancelButtonVisible( b, label );
+ }
+}
+
+
+LLProgressView *LLViewerWindow::getProgressView() const
+{
+ return mProgressView;
+}
+
+void LLViewerWindow::dumpState()
+{
+ llinfos << "LLViewerWindow Active " << S32(mActive) << llendl;
+ llinfos << "mWindow visible " << S32(mWindow->getVisible())
+ << " minimized " << S32(mWindow->getMinimized())
+ << llendl;
+}
+
+void LLViewerWindow::stopGL(BOOL save_state)
+{
+ //Note: --bao
+ //if not necessary, do not change the order of the function calls in this function.
+ //if change something, make sure it will not break anything.
+ //especially be careful to put anything behind gTextureList.destroyGL(save_state);
+ if (!gGLManager.mIsDisabled)
+ {
+ llinfos << "Shutting down GL..." << llendl;
+
+ // Pause texture decode threads (will get unpaused during main loop)
+ LLAppViewer::getTextureCache()->pause();
+ LLAppViewer::getImageDecodeThread()->pause();
+ LLAppViewer::getTextureFetch()->pause();
+
+ gSky.destroyGL();
+ stop_glerror();
+
+ LLManipTranslate::destroyGL() ;
+ stop_glerror();
+
+ gBumpImageList.destroyGL();
+ stop_glerror();
+
+ LLFontGL::destroyAllGL();
+ stop_glerror();
+
+ LLVOAvatar::destroyGL();
+ stop_glerror();
+
+ LLViewerDynamicTexture::destroyGL();
+ stop_glerror();
+
+ if (gPipeline.isInit())
+ {
+ gPipeline.destroyGL();
+ }
+
+ gCone.cleanupGL();
+ gBox.cleanupGL();
+ gSphere.cleanupGL();
+ gCylinder.cleanupGL();
+
+ if(gPostProcess)
+ {
+ gPostProcess->invalidate();
+ }
+
+ gTextureList.destroyGL(save_state);
+ stop_glerror();
+
+ gGLManager.mIsDisabled = TRUE;
+ stop_glerror();
+
+ llinfos << "Remaining allocated texture memory: " << LLImageGL::sGlobalTextureMemoryInBytes << " bytes" << llendl;
+ }
+}
+
+void LLViewerWindow::restoreGL(const std::string& progress_message)
+{
+ //Note: --bao
+ //if not necessary, do not change the order of the function calls in this function.
+ //if change something, make sure it will not break anything.
+ //especially, be careful to put something before gTextureList.restoreGL();
+ if (gGLManager.mIsDisabled)
+ {
+ llinfos << "Restoring GL..." << llendl;
+ gGLManager.mIsDisabled = FALSE;
+
+ initGLDefaults();
+ LLGLState::restoreGL();
+
+ gTextureList.restoreGL();
+
+ // for future support of non-square pixels, and fonts that are properly stretched
+ //LLFontGL::destroyDefaultFonts();
+ initFonts();
+
+ gSky.restoreGL();
+ gPipeline.restoreGL();
+ LLDrawPoolWater::restoreGL();
+ LLManipTranslate::restoreGL();
+
+ gBumpImageList.restoreGL();
+ LLViewerDynamicTexture::restoreGL();
+ LLVOAvatar::restoreGL();
+
+ gResizeScreenTexture = TRUE;
+ gWindowResized = TRUE;
+
+ if (isAgentAvatarValid() && !gAgentAvatarp->isUsingBakedTextures())
+ {
+ LLVisualParamHint::requestHintUpdates();
+ }
+
+ if (!progress_message.empty())
+ {
+ gRestoreGLTimer.reset();
+ gRestoreGL = TRUE;
+ setShowProgress(TRUE);
+ setProgressString(progress_message);
+ }
+ llinfos << "...Restoring GL done" << llendl;
+ if(!LLAppViewer::instance()->restoreErrorTrap())
+ {
+ llwarns << " Someone took over my signal/exception handler (post restoreGL)!" << llendl;
+ }
+
+ }
+}
+
+void LLViewerWindow::initFonts(F32 zoom_factor)
+{
+ LLFontGL::destroyAllGL();
+ // Initialize with possibly different zoom factor
+ LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"),
+ mDisplayScale.mV[VX] * zoom_factor,
+ mDisplayScale.mV[VY] * zoom_factor,
+ gDirUtilp->getAppRODataDir(),
+ LLUI::getXUIPaths());
+ // Force font reloads, which can be very slow
+ LLFontGL::loadDefaultFonts();
+}
+
+void LLViewerWindow::requestResolutionUpdate()
+{
+ mResDirty = true;
+}
+
+void LLViewerWindow::checkSettings()
+{
+ if (mStatesDirty)
+ {
+ gGL.refreshState();
+ LLViewerShaderMgr::instance()->setShaders();
+ mStatesDirty = false;
+ }
+
+ // We want to update the resolution AFTER the states getting refreshed not before.
+ if (mResDirty)
+ {
+ reshape(getWindowWidthRaw(), getWindowHeightRaw());
+ mResDirty = false;
+ }
+}
+
+void LLViewerWindow::restartDisplay(BOOL show_progress_bar)
+{
+ llinfos << "Restaring GL" << llendl;
+ stopGL();
+ if (show_progress_bar)
+ {
+ restoreGL(LLTrans::getString("ProgressChangingResolution"));
+ }
+ else
+ {
+ restoreGL();
+ }
+}
+
+BOOL LLViewerWindow::changeDisplaySettings(LLCoordScreen size, BOOL disable_vsync, BOOL show_progress_bar)
+{
+ //BOOL was_maximized = gSavedSettings.getBOOL("WindowMaximized");
+
+ //gResizeScreenTexture = TRUE;
+
+ //U32 fsaa = gSavedSettings.getU32("RenderFSAASamples");
+ //U32 old_fsaa = mWindow->getFSAASamples();
+
+ // if not maximized, use the request size
+ if (!mWindow->getMaximized())
+ {
+ mWindow->setSize(size);
+ }
+
+ //if (fsaa == old_fsaa)
+ {
+ return TRUE;
+ }
+
+/*
+
+ // Close floaters that don't handle settings change
+ LLFloaterReg::hideInstance("snapshot");
+
+ BOOL result_first_try = FALSE;
+ BOOL result_second_try = FALSE;
+
+ LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
+ send_agent_pause();
+ llinfos << "Stopping GL during changeDisplaySettings" << llendl;
+ stopGL();
+ mIgnoreActivate = TRUE;
+ LLCoordScreen old_size;
+ LLCoordScreen old_pos;
+ mWindow->getSize(&old_size);
+
+ //mWindow->setFSAASamples(fsaa);
+
+ result_first_try = mWindow->switchContext(false, size, disable_vsync);
+ if (!result_first_try)
+ {
+ // try to switch back
+ //mWindow->setFSAASamples(old_fsaa);
+ result_second_try = mWindow->switchContext(false, old_size, disable_vsync);
+
+ if (!result_second_try)
+ {
+ // we are stuck...try once again with a minimal resolution?
+ send_agent_resume();
+ mIgnoreActivate = FALSE;
+ return FALSE;
+ }
+ }
+ send_agent_resume();
+
+ llinfos << "Restoring GL during resolution change" << llendl;
+ if (show_progress_bar)
+ {
+ restoreGL(LLTrans::getString("ProgressChangingResolution"));
+ }
+ else
+ {
+ restoreGL();
+ }
+
+ if (!result_first_try)
+ {
+ LLSD args;
+ args["RESX"] = llformat("%d",size.mX);
+ args["RESY"] = llformat("%d",size.mY);
+ LLNotificationsUtil::add("ResolutionSwitchFail", args);
+ size = old_size; // for reshape below
+ }
+
+ BOOL success = result_first_try || result_second_try;
+
+ if (success)
+ {
+ // maximize window if was maximized, else reposition
+ if (was_maximized)
+ {
+ mWindow->maximize();
+ }
+ else
+ {
+ S32 windowX = gSavedSettings.getS32("WindowX");
+ S32 windowY = gSavedSettings.getS32("WindowY");
+
+ mWindow->setPosition(LLCoordScreen ( windowX, windowY ) );
+ }
+ }
+
+ mIgnoreActivate = FALSE;
+ gFocusMgr.setKeyboardFocus(keyboard_focus);
+
+ return success;
+
+ */
+}
+
+F32 LLViewerWindow::getWorldViewAspectRatio() const
+{
+ F32 world_aspect = (F32)mWorldViewRectRaw.getWidth() / (F32)mWorldViewRectRaw.getHeight();
+ return world_aspect;
+}
+
+void LLViewerWindow::calcDisplayScale()
+{
+ F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor");
+ LLVector2 display_scale;
+ display_scale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f));
+ display_scale *= ui_scale_factor;
+
+ // limit minimum display scale
+ if (display_scale.mV[VX] < MIN_DISPLAY_SCALE || display_scale.mV[VY] < MIN_DISPLAY_SCALE)
+ {
+ display_scale *= MIN_DISPLAY_SCALE / llmin(display_scale.mV[VX], display_scale.mV[VY]);
+ }
+
+ if (display_scale != mDisplayScale)
+ {
+ llinfos << "Setting display scale to " << display_scale << llendl;
+
+ mDisplayScale = display_scale;
+ // Init default fonts
+ initFonts();
+ }
+}
+
+//static
+LLRect LLViewerWindow::calcScaledRect(const LLRect & rect, const LLVector2& display_scale)
+{
+ LLRect res = rect;
+ res.mLeft = llround((F32)res.mLeft / display_scale.mV[VX]);
+ res.mRight = llround((F32)res.mRight / display_scale.mV[VX]);
+ res.mBottom = llround((F32)res.mBottom / display_scale.mV[VY]);
+ res.mTop = llround((F32)res.mTop / display_scale.mV[VY]);
+
+ return res;
+}
+
+S32 LLViewerWindow::getChatConsoleBottomPad()
+{
+ S32 offset = 0;
+
+ if(LLBottomTray::instanceExists())
+ offset += LLBottomTray::getInstance()->getRect().getHeight();
+
+ return offset;
+}
+
+LLRect LLViewerWindow::getChatConsoleRect()
+{
+ LLRect full_window(0, getWindowHeightScaled(), getWindowWidthScaled(), 0);
+ LLRect console_rect = full_window;
+
+ const S32 CONSOLE_PADDING_TOP = 24;
+ const S32 CONSOLE_PADDING_LEFT = 24;
+ const S32 CONSOLE_PADDING_RIGHT = 10;
+
+ console_rect.mTop -= CONSOLE_PADDING_TOP;
+ console_rect.mBottom += getChatConsoleBottomPad();
+
+ console_rect.mLeft += CONSOLE_PADDING_LEFT;
+
+ static const BOOL CHAT_FULL_WIDTH = gSavedSettings.getBOOL("ChatFullWidth");
+
+ if (CHAT_FULL_WIDTH)
+ {
+ console_rect.mRight -= CONSOLE_PADDING_RIGHT;
+ }
+ else
+ {
+ // Make console rect somewhat narrow so having inventory open is
+ // less of a problem.
+ console_rect.mRight = console_rect.mLeft + 2 * getWindowWidthScaled() / 3;
+ }
+
+ return console_rect;
+}
+//----------------------------------------------------------------------------
+
+
+//static
+bool LLViewerWindow::onAlert(const LLSD& notify)
+{
+ LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID());
+
+ if (gNoRender)
+ {
+ llinfos << "Alert: " << notification->getName() << llendl;
+ notification->respond(LLSD::emptyMap());
+ LLNotifications::instance().cancel(notification);
+ return false;
+ }
+
+ // If we're in mouselook, the mouse is hidden and so the user can't click
+ // the dialog buttons. In that case, change to First Person instead.
+ if( gAgentCamera.cameraMouselook() )
+ {
+ gAgentCamera.changeCameraToDefault();
+ }
+ return false;
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// LLPickInfo
+//
+LLPickInfo::LLPickInfo()
+ : mKeyMask(MASK_NONE),
+ mPickCallback(NULL),
+ mPickType(PICK_INVALID),
+ mWantSurfaceInfo(FALSE),
+ mObjectFace(-1),
+ mUVCoords(-1.f, -1.f),
+ mSTCoords(-1.f, -1.f),
+ mXYCoords(-1, -1),
+ mIntersection(),
+ mNormal(),
+ mBinormal(),
+ mHUDIcon(NULL),
+ mPickTransparent(FALSE)
+{
+}
+
+LLPickInfo::LLPickInfo(const LLCoordGL& mouse_pos,
+ MASK keyboard_mask,
+ BOOL pick_transparent,
+ BOOL pick_uv_coords,
+ void (*pick_callback)(const LLPickInfo& pick_info))
+ : mMousePt(mouse_pos),
+ mKeyMask(keyboard_mask),
+ mPickCallback(pick_callback),
+ mPickType(PICK_INVALID),
+ mWantSurfaceInfo(pick_uv_coords),
+ mObjectFace(-1),
+ mUVCoords(-1.f, -1.f),
+ mSTCoords(-1.f, -1.f),
+ mXYCoords(-1, -1),
+ mNormal(),
+ mBinormal(),
+ mHUDIcon(NULL),
+ mPickTransparent(pick_transparent)
+{
+}
+
+void LLPickInfo::fetchResults()
+{
+
+ S32 face_hit = -1;
+ LLVector3 intersection, normal, binormal;
+ LLVector2 uv;
+
+ LLHUDIcon* hit_icon = gViewerWindow->cursorIntersectIcon(mMousePt.mX, mMousePt.mY, 512.f, &intersection);
+
+ F32 icon_dist = 0.f;
+ if (hit_icon)
+ {
+ icon_dist = (LLViewerCamera::getInstance()->getOrigin()-intersection).magVec();
+ }
+ LLViewerObject* hit_object = gViewerWindow->cursorIntersect(mMousePt.mX, mMousePt.mY, 512.f,
+ NULL, -1, mPickTransparent, &face_hit,
+ &intersection, &uv, &normal, &binormal);
+
+ mPickPt = mMousePt;
+
+ U32 te_offset = face_hit > -1 ? face_hit : 0;
+
+ //unproject relative clicked coordinate from window coordinate using GL
+
+ LLViewerObject* objectp = hit_object;
+
+ if (hit_icon &&
+ (!objectp ||
+ icon_dist < (LLViewerCamera::getInstance()->getOrigin()-intersection).magVec()))
+ {
+ // was this name referring to a hud icon?
+ mHUDIcon = hit_icon;
+ mPickType = PICK_ICON;
+ mPosGlobal = mHUDIcon->getPositionGlobal();
+ }
+ else if (objectp)
+ {
+ if( objectp->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH )
+ {
+ // Hit land
+ mPickType = PICK_LAND;
+ mObjectID.setNull(); // land has no id
+
+ // put global position into land_pos
+ LLVector3d land_pos;
+ if (!gViewerWindow->mousePointOnLandGlobal(mPickPt.mX, mPickPt.mY, &land_pos))
+ {
+ // The selected point is beyond the draw distance or is otherwise
+ // not selectable. Return before calling mPickCallback().
+ return;
+ }
+
+ // Fudge the land focus a little bit above ground.
+ mPosGlobal = land_pos + LLVector3d::z_axis * 0.1f;
+ }
+ else
+ {
+ if(isFlora(objectp))
+ {
+ mPickType = PICK_FLORA;
+ }
+ else
+ {
+ mPickType = PICK_OBJECT;
+ }
+ mObjectOffset = gAgentCamera.calcFocusOffset(objectp, intersection, mPickPt.mX, mPickPt.mY);
+ mObjectID = objectp->mID;
+ mObjectFace = (te_offset == NO_FACE) ? -1 : (S32)te_offset;
+
+ mPosGlobal = gAgent.getPosGlobalFromAgent(intersection);
+
+ if (mWantSurfaceInfo)
+ {
+ getSurfaceInfo();
+ }
+ }
+ }
+
+ if (mPickCallback)
+ {
+ mPickCallback(*this);
+ }
+}
+
+LLPointer<LLViewerObject> LLPickInfo::getObject() const
+{
+ return gObjectList.findObject( mObjectID );
+}
+
+void LLPickInfo::updateXYCoords()
+{
+ if (mObjectFace > -1)
+ {
+ const LLTextureEntry* tep = getObject()->getTE(mObjectFace);
+ LLPointer<LLViewerTexture> imagep = LLViewerTextureManager::getFetchedTexture(tep->getID());
+ if(mUVCoords.mV[VX] >= 0.f && mUVCoords.mV[VY] >= 0.f && imagep.notNull())
+ {
+ mXYCoords.mX = llround(mUVCoords.mV[VX] * (F32)imagep->getWidth());
+ mXYCoords.mY = llround((1.f - mUVCoords.mV[VY]) * (F32)imagep->getHeight());
+ }
+ }
+}
+
+void LLPickInfo::getSurfaceInfo()
+{
+ // set values to uninitialized - this is what we return if no intersection is found
+ mObjectFace = -1;
+ mUVCoords = LLVector2(-1, -1);
+ mSTCoords = LLVector2(-1, -1);
+ mXYCoords = LLCoordScreen(-1, -1);
+ mIntersection = LLVector3(0,0,0);
+ mNormal = LLVector3(0,0,0);
+ mBinormal = LLVector3(0,0,0);
+
+ LLViewerObject* objectp = getObject();
+
+ if (objectp)
+ {
+ if (gViewerWindow->cursorIntersect(llround((F32)mMousePt.mX), llround((F32)mMousePt.mY), 1024.f,
+ objectp, -1, mPickTransparent,
+ &mObjectFace,
+ &mIntersection,
+ &mSTCoords,
+ &mNormal,
+ &mBinormal))
+ {
+ // if we succeeded with the intersect above, compute the texture coordinates:
+
+ if (objectp->mDrawable.notNull() && mObjectFace > -1)
+ {
+ LLFace* facep = objectp->mDrawable->getFace(mObjectFace);
+
+ mUVCoords = facep->surfaceToTexture(mSTCoords, mIntersection, mNormal);
+ }
+
+ // and XY coords:
+ updateXYCoords();
+
+ }
+ }
+}
+
+
+/* code to get UV via a special UV render - removed in lieu of raycast method
+LLVector2 LLPickInfo::pickUV()
+{
+ LLVector2 result(-1.f, -1.f);
+
+ LLViewerObject* objectp = getObject();
+ if (!objectp)
+ {
+ return result;
+ }
+
+ if (mObjectFace > -1 &&
+ objectp->mDrawable.notNull() && objectp->getPCode() == LL_PCODE_VOLUME &&
+ mObjectFace < objectp->mDrawable->getNumFaces())
+ {
+ S32 scaled_x = llround((F32)mPickPt.mX * gViewerWindow->getDisplayScale().mV[VX]);
+ S32 scaled_y = llround((F32)mPickPt.mY * gViewerWindow->getDisplayScale().mV[VY]);
+ const S32 UV_PICK_WIDTH = 5;
+ const S32 UV_PICK_HALF_WIDTH = (UV_PICK_WIDTH - 1) / 2;
+ U8 uv_pick_buffer[UV_PICK_WIDTH * UV_PICK_WIDTH * 4];
+ LLFace* facep = objectp->mDrawable->getFace(mObjectFace);
+ if (facep)
+ {
+ LLGLState scissor_state(GL_SCISSOR_TEST);
+ scissor_state.enable();
+ LLViewerCamera::getInstance()->setPerspective(FOR_SELECTION, scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH, FALSE);
+ //glViewport(scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH);
+ glScissor(scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH);
+
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ facep->renderSelectedUV();
+
+ glReadPixels(scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH, GL_RGBA, GL_UNSIGNED_BYTE, uv_pick_buffer);
+ U8* center_pixel = &uv_pick_buffer[4 * ((UV_PICK_WIDTH * UV_PICK_HALF_WIDTH) + UV_PICK_HALF_WIDTH + 1)];
+
+ result.mV[VX] = (F32)((center_pixel[VGREEN] & 0xf) + (16.f * center_pixel[VRED])) / 4095.f;
+ result.mV[VY] = (F32)((center_pixel[VGREEN] >> 4) + (16.f * center_pixel[VBLUE])) / 4095.f;
+ }
+ }
+
+ return result;
+} */
+
+
+//static
+bool LLPickInfo::isFlora(LLViewerObject* object)
+{
+ if (!object) return false;
+
+ LLPCode pcode = object->getPCode();
+
+ if( (LL_PCODE_LEGACY_GRASS == pcode)
+ || (LL_PCODE_LEGACY_TREE == pcode)
+ || (LL_PCODE_TREE_NEW == pcode))
+ {
+ return true;
+ }
+ return false;
+}
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index cec2942b35..d79d660724 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -673,4 +673,5 @@ with the same filename but different name <texture name="Yellow_Gradient" file_name="windows/yellow_gradient.png"/> <texture name="Popup_Caution" file_name="icons/pop_up_caution.png"/> + <texture name="Camera_Drag_Dot" file_name="world/CameraDragDot.png"/> </textures> diff --git a/indra/newview/skins/default/textures/world/CameraDragDot.png b/indra/newview/skins/default/textures/world/CameraDragDot.png Binary files differnew file mode 100644 index 0000000000..57698e1956 --- /dev/null +++ b/indra/newview/skins/default/textures/world/CameraDragDot.png |