From 266b3843b75fb9b8da7d2b3c824224a1b94697a5 Mon Sep 17 00:00:00 2001
From: callum <none@none>
Date: Tue, 21 Sep 2010 16:41:06 -0700
Subject: EXP-94 Disable local file system access

---
 indra/newview/app_settings/settings.xml | 11 ++++
 indra/newview/llfilepicker.cpp          | 96 +++++++++++++++++++++++++++++++++
 indra/newview/llfilepicker.h            |  4 ++
 3 files changed, 111 insertions(+)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index feb5ebc16d..b28a02551e 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -4537,6 +4537,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>LocalFileSystemBrowsingEnabled</key>
+    <map>
+      <key>Comment</key>
+      <string>Enable/disable access to the local file system via the file picker</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
   <key>LoginSRVTimeout</key>
   <map>
     <key>Comment</key>
diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp
index c14be89641..f0840774bd 100644
--- a/indra/newview/llfilepicker.cpp
+++ b/indra/newview/llfilepicker.cpp
@@ -33,6 +33,7 @@
 #include "lldir.h"
 #include "llframetimer.h"
 #include "lltrans.h"
+#include "llviewercontrol.h"
 #include "llwindow.h"	// beforeDialog()
 
 #if LL_SDL
@@ -104,6 +105,20 @@ LLFilePicker::~LLFilePicker()
 	// nothing
 }
 
+// utility function to check if access to local file system via file browser 
+// is enabled and if not, tidy up and indicate we're not allowed to do this.
+bool LLFilePicker::check_local_file_access_enabled()
+{
+	// if local file browsing is turned off, return without opening dialog
+	bool local_file_system_browsing_enabled = gSavedSettings.getBOOL("LocalFileSystemBrowsingEnabled");
+	if ( ! local_file_system_browsing_enabled )
+	{
+		mFiles.clear();
+		return false;
+	}
+
+	return true;
+}
 
 const std::string LLFilePicker::getFirstFile()
 {
@@ -203,6 +218,12 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter)
 	}
 	BOOL success = FALSE;
 
+	// if local file browsing is turned off, return without opening dialog
+	if ( check_local_file_access_enabled() == false )
+	{
+		return FALSE;
+	}
+
 	// don't provide default file selection
 	mFilesW[0] = '\0';
 
@@ -241,6 +262,12 @@ BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter)
 	}
 	BOOL success = FALSE;
 
+	// if local file browsing is turned off, return without opening dialog
+	if ( check_local_file_access_enabled() == false )
+	{
+		return FALSE;
+	}
+
 	// don't provide default file selection
 	mFilesW[0] = '\0';
 
@@ -304,6 +331,12 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename)
 	}
 	BOOL success = FALSE;
 
+	// if local file browsing is turned off, return without opening dialog
+	if ( check_local_file_access_enabled() == false )
+	{
+		return FALSE;
+	}
+
 	mOFN.lpstrFile = mFilesW;
 	if (!filename.empty())
 	{
@@ -581,6 +614,12 @@ OSStatus	LLFilePicker::doNavChooseDialog(ELoadFilter filter)
 	NavDialogRef	navRef = NULL;
 	NavReplyRecord	navReply;
 
+	// if local file browsing is turned off, return without opening dialog
+	if ( check_local_file_access_enabled() == false )
+	{
+		return FALSE;
+	}
+
 	memset(&navReply, 0, sizeof(navReply));
 	
 	// NOTE: we are passing the address of a local variable here.  
@@ -809,6 +848,12 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter)
 
 	BOOL success = FALSE;
 
+	// if local file browsing is turned off, return without opening dialog
+	if ( check_local_file_access_enabled() == false )
+	{
+		return FALSE;
+	}
+
 	OSStatus	error = noErr;
 	
 	reset();
@@ -845,6 +890,12 @@ BOOL LLFilePicker::getMultipleOpenFiles(ELoadFilter filter)
 
 	BOOL success = FALSE;
 
+	// if local file browsing is turned off, return without opening dialog
+	if ( check_local_file_access_enabled() == false )
+	{
+		return FALSE;
+	}
+
 	OSStatus	error = noErr;
 
 	reset();
@@ -876,6 +927,12 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename)
 	BOOL success = FALSE;
 	OSStatus	error = noErr;
 
+	// if local file browsing is turned off, return without opening dialog
+	if ( check_local_file_access_enabled() == false )
+	{
+		return FALSE;
+	}
+
 	reset();
 	
 	mNavOptions.optionFlags &= ~kNavAllowMultipleFiles;
@@ -1100,6 +1157,12 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename
 {
 	BOOL rtn = FALSE;
 
+	// if local file browsing is turned off, return without opening dialog
+	if ( check_local_file_access_enabled() == false )
+	{
+		return FALSE;
+	}
+
 	gViewerWindow->mWindow->beforeDialog();
 
 	reset();
@@ -1189,6 +1252,12 @@ BOOL LLFilePicker::getOpenFile( ELoadFilter filter )
 {
 	BOOL rtn = FALSE;
 
+	// if local file browsing is turned off, return without opening dialog
+	if ( check_local_file_access_enabled() == false )
+	{
+		return FALSE;
+	}
+
 	gViewerWindow->mWindow->beforeDialog();
 
 	reset();
@@ -1233,6 +1302,12 @@ BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter )
 {
 	BOOL rtn = FALSE;
 
+	// if local file browsing is turned off, return without opening dialog
+	if ( check_local_file_access_enabled() == false )
+	{
+		return FALSE;
+	}
+
 	gViewerWindow->mWindow->beforeDialog();
 
 	reset();
@@ -1263,6 +1338,13 @@ BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter )
 
 BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename )
 {
+	// if local file browsing is turned off, return without opening dialog
+	// (Even though this is a stub, I think we still should not return anything at all)
+	if ( check_local_file_access_enabled() == false )
+	{
+		return FALSE;
+	}
+
 	reset();
 	
 	llinfos << "getSaveFile suggested filename is [" << filename
@@ -1277,6 +1359,13 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename
 
 BOOL LLFilePicker::getOpenFile( ELoadFilter filter )
 {
+	// if local file browsing is turned off, return without opening dialog
+	// (Even though this is a stub, I think we still should not return anything at all)
+	if ( check_local_file_access_enabled() == false )
+	{
+		return FALSE;
+	}
+
 	reset();
 	
 	// HACK: Static filenames for 'open' until we implement filepicker
@@ -1295,6 +1384,13 @@ BOOL LLFilePicker::getOpenFile( ELoadFilter filter )
 
 BOOL LLFilePicker::getMultipleOpenFiles( ELoadFilter filter )
 {
+	// if local file browsing is turned off, return without opening dialog
+	// (Even though this is a stub, I think we still should not return anything at all)
+	if ( check_local_file_access_enabled() == false )
+	{
+		return FALSE;
+	}
+
 	reset();
 	return FALSE;
 }
diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h
index 5819ac4fd8..596bfa3e69 100644
--- a/indra/newview/llfilepicker.h
+++ b/indra/newview/llfilepicker.h
@@ -140,6 +140,10 @@ private:
 		//FILENAME_BUFFER_SIZE = 65536
 		FILENAME_BUFFER_SIZE = 65000
 	};
+
+	// utility function to check if access to local file system via file browser 
+	// is enabled and if not, tidy up and indicate we're not allowed to do this.
+	bool check_local_file_access_enabled();
 	
 #if LL_WINDOWS
 	OPENFILENAMEW mOFN;				// for open and save dialogs
-- 
cgit v1.2.3


From 7648bb425ae106ce0268c7ff535b054de6f6a318 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Wed, 22 Sep 2010 12:25:40 -0700
Subject: EXP-111 WIP Automatically provide default responses to all
 notifications

---
 indra/newview/app_settings/settings.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index feb5ebc16d..143574264d 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -3914,7 +3914,7 @@
       <key>Comment</key>
       <string>Ignore all notifications so we never need user input on them.</string>
       <key>Persist</key>
-      <integer>0</integer>
+      <integer>1</integer>
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
-- 
cgit v1.2.3


From f8a17515f592a1d759ca2c79f80b2ed032af2ebe Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Wed, 22 Sep 2010 12:27:26 -0700
Subject: EXP-109 WIP strip down main_view.xml made menu keyboard access only
 work when menus are visible dummy widgets are now added with a parent view
 that is invisible popupview can now be default-built

---
 indra/newview/llpopupview.cpp                    |  3 ++-
 indra/newview/llpopupview.h                      |  2 +-
 indra/newview/llviewerwindow.cpp                 |  2 +-
 indra/newview/skins/minimal/xui/en/main_view.xml | 27 ++++++++++++++++++++++++
 4 files changed, 31 insertions(+), 3 deletions(-)
 create mode 100644 indra/newview/skins/minimal/xui/en/main_view.xml

(limited to 'indra/newview')

diff --git a/indra/newview/llpopupview.cpp b/indra/newview/llpopupview.cpp
index 499b6a8f5f..18035c42f4 100644
--- a/indra/newview/llpopupview.cpp
+++ b/indra/newview/llpopupview.cpp
@@ -40,7 +40,8 @@ bool view_visible(LLView* viewp)
 }
 
 
-LLPopupView::LLPopupView()
+LLPopupView::LLPopupView(const LLPopupView::Params& p)
+: LLPanel(p)
 {
 	// register ourself as handler of UI popups
 	LLUI::setPopupFuncs(boost::bind(&LLPopupView::addPopup, this, _1), boost::bind(&LLPopupView::removePopup, this, _1), boost::bind(&LLPopupView::clearPopups, this));
diff --git a/indra/newview/llpopupview.h b/indra/newview/llpopupview.h
index fec4afd79c..b378f61984 100644
--- a/indra/newview/llpopupview.h
+++ b/indra/newview/llpopupview.h
@@ -32,7 +32,7 @@
 class LLPopupView : public LLPanel
 {
 public:
-	LLPopupView();
+	LLPopupView(const Params& p = LLPanel::Params());
 	~LLPopupView();
 
 	/*virtual*/ void draw();
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 7f8b7fba9f..19f51b2bbe 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1524,7 +1524,7 @@ void LLViewerWindow::initBase()
 	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->findChild<LLPopupView>("popup_holder");
+	mPopupView = main_view->getChild<LLPopupView>("popup_holder");
 	mHintHolder = main_view->getChild<LLView>("hint_holder")->getHandle();
 
 	// Constrain floaters to inside the menu and status bar regions.
diff --git a/indra/newview/skins/minimal/xui/en/main_view.xml b/indra/newview/skins/minimal/xui/en/main_view.xml
new file mode 100644
index 0000000000..c793b1b813
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/main_view.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ follows="left|right|top|bottom"
+ height="768"
+ layout="topleft"
+ left="0"
+ mouse_opaque="false"
+ tab_stop="false" 
+ name="main_view"
+ width="1024">
+  <view top="0"
+        follows="all"
+        height="768"
+        left="0"
+        mouse_opaque="false"
+        name="world_view_rect"
+        width="1024"/>
+  <panel top="0"
+         follows="all"
+         height="768"
+         mouse_opaque="true"
+         name="progress_view"
+         filename="panel_progress.xml"
+         class="progress_view"
+         width="1024"
+         visible="false"/>
+</panel>
-- 
cgit v1.2.3


From aa7d505882f07cffea8b7cd145296f3c114c3f50 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Wed, 22 Sep 2010 12:27:48 -0700
Subject: EXP-108 FIX Create new "minimal" UI skin

---
 indra/newview/llappviewer.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 333c92e50d..1fd3632b85 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2182,8 +2182,8 @@ bool LLAppViewer::initConfiguration()
     if(skinfolder && LLStringUtil::null != skinfolder->getValue().asString())
     {   
 		// hack to force the skin to default.
-        //gDirUtilp->setSkinFolder(skinfolder->getValue().asString());
-		gDirUtilp->setSkinFolder("default");
+        gDirUtilp->setSkinFolder(skinfolder->getValue().asString());
+		//gDirUtilp->setSkinFolder("default");
     }
 
     mYieldTime = gSavedSettings.getS32("YieldTime");
-- 
cgit v1.2.3


From 18404624e0c9c2544b0ebba2b9758a606d2fe574 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Wed, 22 Sep 2010 15:02:23 -0700
Subject: support older use of "IgnoreAllNotifications" by command line option
 "nonotifications" such that value isn't saved

---
 indra/newview/llappviewer.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 1fd3632b85..02a8c3e674 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2135,7 +2135,7 @@ bool LLAppViewer::initConfiguration()
 
 	if (clp.hasOption("nonotifications"))
 	{
-		gSavedSettings.setBOOL("IgnoreAllNotifications", TRUE);
+		gSavedSettings.getControl("IgnoreAllNotifications")->setValue(true, false);
 	}
 	
 	if (clp.hasOption("debugsession"))
-- 
cgit v1.2.3


From 636c86782b9c8a37996aaf01868f713214c54584 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Wed, 22 Sep 2010 16:12:04 -0700
Subject: cleaned up notifications.xml and made global notifications toggle not
 use or modify saved responses

---
 indra/newview/app_settings/cmd_line.xml            |  2 +-
 .../newview/skins/default/xui/en/notifications.xml | 44 +++++-----------------
 2 files changed, 10 insertions(+), 36 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/cmd_line.xml b/indra/newview/app_settings/cmd_line.xml
index 00d69f805e..962c4e9d36 100644
--- a/indra/newview/app_settings/cmd_line.xml
+++ b/indra/newview/app_settings/cmd_line.xml
@@ -149,7 +149,7 @@
     <key>nonotifications</key>
     <map>
       <key>desc</key>
-      <string>User will not get any notifications. NOTE: All notifications that occur will get added to ignore file for future runs.</string>
+      <string>User will not get any notifications.</string>
       <key>map-to</key>
       <string>IgnoreAllNotifications</string>      
     </map>    
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index e1aecda151..5966db9d51 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -2069,7 +2069,7 @@ Would you be my friend?
       <button
        default="true"
        index="0"
-       name="Offer"
+       name="OK"
        text="OK"/>
       <button
        index="1"
@@ -2091,7 +2091,7 @@ Would you be my friend?
       <button
        default="true"
        index="0"
-       name="Offer"
+       name="OK"
        text="OK"/>
       <button
        index="1"
@@ -2114,7 +2114,7 @@ Would you be my friend?
       <button
        default="true"
        index="0"
-       name="Offer"
+       name="OK"
        text="OK"/>
       <button
        index="1"
@@ -4810,24 +4810,6 @@ Some terms in your search query were excluded due to content restrictions as cla
 Please select at least one type of content to search (General, Moderate, or Adult).
   </notification>
 
-  <notification
-   icon="notify.tga"
-   name="GroupVote"
-   type="notify">
-[NAME] has proposed to vote on:
-[MESSAGE]
-    <form name="form">
-      <button
-       index="0"
-       name="VoteNow"
-       text="Vote Now"/>
-      <button
-       index="1"
-       name="Later"
-       text="Later"/>
-    </form>
-  </notification>
-
   <notification
    icon="notify.tga"
    name="SystemMessage"
@@ -6313,13 +6295,9 @@ Avatar '[NAME]' left appearance mode.
    type="alertmodal">
 We're having trouble connecting using [PROTOCOL] [HOSTID].
 Please check your network and firewall setup.
-    <form name="form">
-      <button
-       default="true"
-       index="0"
-       name="OK"
-       text="OK"/>
-    </form>
+    <usetemplate
+     name="okbutton"
+     yestext="OK"/>
   </notification>
 
   <notification
@@ -6332,13 +6310,9 @@ We're having trouble connecting to your voice server:
 
 Voice communications will not be available.
 Please check your network and firewall setup.
-    <form name="form">
-      <button
-       default="true"
-       index="0"
-       name="OK"
-       text="OK"/>
-    </form>
+    <usetemplate
+     name="okbutton"
+     yestext="OK"/>
   </notification>
 
   <notification
-- 
cgit v1.2.3


From 57b8571a8acd559b7a92c2d5ffbfe96b0c4b5b98 Mon Sep 17 00:00:00 2001
From: Monroe Linden <monroe@lindenlab.com>
Date: Fri, 24 Sep 2010 16:17:12 -0700
Subject: Added the VoiceDisableMic debug setting to completely disable the
 ability to open the mic.

Also hoisted PTT key handling from LLVivoxVoiceClient up to LLVoiceClient.  This cleans up LLVoiceModuleInterface a bit and makes the PTT logic more centralized.

Reviewed by Richard.
---
 indra/newview/app_settings/settings.xml |  11 ++
 indra/newview/llvoiceclient.cpp         | 138 ++++++++++++++++++++-----
 indra/newview/llvoiceclient.h           |  34 +++---
 indra/newview/llvoicevivox.cpp          | 177 +++-----------------------------
 indra/newview/llvoicevivox.h            |  32 +-----
 5 files changed, 159 insertions(+), 233 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 9000a9e530..a83291b530 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -11366,6 +11366,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>VoiceDisableMic</key>
+    <map>
+      <key>Comment</key>
+      <string>Completely disable the ability to open the mic.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>VoiceEffectExpiryWarningTime</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index 6c44f639ec..730f022c50 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -35,6 +35,7 @@
 #include "llnotificationsutil.h"
 #include "llsdserialize.h"
 #include "llui.h"
+#include "llkeyboard.h"
 
 const F32 LLVoiceClient::OVERDRIVEN_POWER_LEVEL = 0.7f;
 
@@ -113,8 +114,18 @@ LLVoiceClient::LLVoiceClient()
 	mVoiceModule(NULL),
 	m_servicePump(NULL),
 	mVoiceEffectEnabled(LLCachedControl<bool>(gSavedSettings, "VoiceMorphingEnabled")),
-	mVoiceEffectDefault(LLCachedControl<std::string>(gSavedPerAccountSettings, "VoiceEffectDefault"))
+	mVoiceEffectDefault(LLCachedControl<std::string>(gSavedPerAccountSettings, "VoiceEffectDefault")),
+	mPTTDirty(true),
+	mPTT(true),
+	mUsePTT(true),
+	mPTTIsMiddleMouse(false),
+	mPTTKey(0),
+	mPTTIsToggle(false),
+	mUserPTTState(false),
+	mMuteMic(false),
+	mDisableMic(false)
 {
+	updateSettings();
 }
 
 //---------------------------------------------------
@@ -173,6 +184,14 @@ const LLVoiceVersionInfo LLVoiceClient::getVersion()
 
 void LLVoiceClient::updateSettings()
 {
+	setUsePTT(gSavedSettings.getBOOL("PTTCurrentlyEnabled"));
+	std::string keyString = gSavedSettings.getString("PushToTalkButton");
+	setPTTKey(keyString);
+	setPTTIsToggle(gSavedSettings.getBOOL("PushToTalkToggle"));
+	mDisableMic = gSavedSettings.getBOOL("VoiceDisableMic");
+
+	updateMicMuteLogic();
+
 	if (mVoiceModule) mVoiceModule->updateSettings();
 }
 
@@ -481,6 +500,26 @@ void LLVoiceClient::setVoiceEnabled(bool enabled)
 	if (mVoiceModule) mVoiceModule->setVoiceEnabled(enabled);
 }
 
+void LLVoiceClient::updateMicMuteLogic()
+{
+	// If not configured to use PTT, the mic should be open (otherwise the user will be unable to speak).
+	bool new_mic_mute = false;
+	
+	if(mUsePTT)
+	{
+		// If configured to use PTT, track the user state.
+		new_mic_mute = !mUserPTTState;
+	}
+
+	if(mMuteMic || mDisableMic)
+	{
+		// Either of these always overrides any other PTT setting.
+		new_mic_mute = true;
+	}
+	
+	if (mVoiceModule) mVoiceModule->setMuteMic(new_mic_mute);
+}
+
 void LLVoiceClient::setLipSyncEnabled(BOOL enabled)
 {
 	if (mVoiceModule) mVoiceModule->setLipSyncEnabled(enabled);
@@ -500,7 +539,8 @@ BOOL LLVoiceClient::lipSyncEnabled()
 
 void LLVoiceClient::setMuteMic(bool muted)
 {
-	if (mVoiceModule) mVoiceModule->setMuteMic(muted);
+	mMuteMic = muted;
+	updateMicMuteLogic();
 }
 
 
@@ -509,64 +549,116 @@ void LLVoiceClient::setMuteMic(bool muted)
 
 void LLVoiceClient::setUserPTTState(bool ptt)
 {
-	if (mVoiceModule) mVoiceModule->setUserPTTState(ptt);
+	mUserPTTState = ptt;
+	updateMicMuteLogic();
 }
 
 bool LLVoiceClient::getUserPTTState()
 {
-	if (mVoiceModule) 
-	{
-		return mVoiceModule->getUserPTTState();
-	}
-	else
-	{
-		return false;
-	}
+	return mUserPTTState;
 }
 
 void LLVoiceClient::setUsePTT(bool usePTT)
 {
-	if (mVoiceModule) mVoiceModule->setUsePTT(usePTT);
+	if(usePTT && !mUsePTT)
+	{
+		// When the user turns on PTT, reset the current state.
+		mUserPTTState = false;
+	}
+	mUsePTT = usePTT;
+	
+	updateMicMuteLogic();
 }
 
 void LLVoiceClient::setPTTIsToggle(bool PTTIsToggle)
 {
-	if (mVoiceModule) mVoiceModule->setPTTIsToggle(PTTIsToggle);
+	if(!PTTIsToggle && mPTTIsToggle)
+	{
+		// When the user turns off toggle, reset the current state.
+		mUserPTTState = false;
+	}
+	
+	mPTTIsToggle = PTTIsToggle;
+
+	updateMicMuteLogic();
 }
 
 bool LLVoiceClient::getPTTIsToggle()
 {
-	if (mVoiceModule) 
+	return mPTTIsToggle;
+}
+
+void LLVoiceClient::setPTTKey(std::string &key)
+{
+	if(key == "MiddleMouse")
 	{
-		return mVoiceModule->getPTTIsToggle();
+		mPTTIsMiddleMouse = true;
 	}
-	else {
-		return false;
+	else
+	{
+		mPTTIsMiddleMouse = false;
+		if(!LLKeyboard::keyFromString(key, &mPTTKey))
+		{
+			// If the call failed, don't match any key.
+			key = KEY_NONE;
+		}
 	}
-
 }
 
 void LLVoiceClient::inputUserControlState(bool down)
 {
-	if (mVoiceModule) mVoiceModule->inputUserControlState(down);	
+	if(mPTTIsToggle)
+	{
+		if(down) // toggle open-mic state on 'down'                                                        
+		{
+			toggleUserPTTState();
+		}
+	}
+	else // set open-mic state as an absolute                                                                  
+	{
+		setUserPTTState(down);
+	}
 }
 
 void LLVoiceClient::toggleUserPTTState(void)
 {
-	if (mVoiceModule) mVoiceModule->toggleUserPTTState();
+	setUserPTTState(!getUserPTTState());
 }
 
 void LLVoiceClient::keyDown(KEY key, MASK mask)
 {	
-	if (mVoiceModule) mVoiceModule->keyDown(key, mask);
+	if (gKeyboard->getKeyRepeated(key))
+	{
+		// ignore auto-repeat keys                                                                         
+		return;
+	}
+	
+	if(!mPTTIsMiddleMouse)
+	{
+		bool down = (mPTTKey != KEY_NONE)
+		&& gKeyboard->getKeyDown(mPTTKey);
+		inputUserControlState(down);
+	}
+	
 }
 void LLVoiceClient::keyUp(KEY key, MASK mask)
 {
-	if (mVoiceModule) mVoiceModule->keyUp(key, mask);
+	if(!mPTTIsMiddleMouse)
+	{
+		bool down = (mPTTKey != KEY_NONE)
+		&& gKeyboard->getKeyDown(mPTTKey);
+		inputUserControlState(down);
+	}
 }
 void LLVoiceClient::middleMouseState(bool down)
 {
-	if (mVoiceModule) mVoiceModule->middleMouseState(down);
+	if(mPTTIsMiddleMouse)
+	{
+        if(mPTTIsMiddleMouse)
+        {
+			inputUserControlState(down);
+        }		
+	}
 }
 
 
diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h
index 24d7d7163e..c9aeea35a9 100644
--- a/indra/newview/llvoiceclient.h
+++ b/indra/newview/llvoiceclient.h
@@ -191,25 +191,9 @@ public:
 	virtual void setVoiceEnabled(bool enabled)=0;
 	virtual void setLipSyncEnabled(BOOL enabled)=0;
 	virtual BOOL lipSyncEnabled()=0;	
-	virtual void setMuteMic(bool muted)=0;		// Use this to mute the local mic (for when the client is minimized, etc), ignoring user PTT state.
+	virtual void setMuteMic(bool muted)=0;		// Set the mute state of the local mic.
 	//@}
-	
-	////////////////////////
-	/// @name PTT
-	//@{
-	virtual void setUserPTTState(bool ptt)=0;
-	virtual bool getUserPTTState()=0;
-	virtual void setUsePTT(bool usePTT)=0;
-	virtual void setPTTIsToggle(bool PTTIsToggle)=0;
-	virtual bool getPTTIsToggle()=0;	
-	virtual void toggleUserPTTState(void)=0;
-	virtual void inputUserControlState(bool down)=0;  // interpret any sort of up-down mic-open control input according to ptt-toggle prefs
-	
-	virtual void keyDown(KEY key, MASK mask)=0;
-	virtual void keyUp(KEY key, MASK mask)=0;
-	virtual void middleMouseState(bool down)=0;
-	//@}
-	
+		
 	//////////////////////////
 	/// @name nearby speaker accessors
 	//@{
@@ -406,6 +390,9 @@ public:
 	void setUsePTT(bool usePTT);
 	void setPTTIsToggle(bool PTTIsToggle);
 	bool getPTTIsToggle();	
+	void setPTTKey(std::string &key);
+	
+	void updateMicMuteLogic();
 	
 	BOOL lipSyncEnabled();
 	
@@ -471,6 +458,17 @@ protected:
 
 	LLCachedControl<bool> mVoiceEffectEnabled;
 	LLCachedControl<std::string> mVoiceEffectDefault;
+
+	bool		mPTTDirty;
+	bool		mPTT;
+	
+	bool		mUsePTT;
+	bool		mPTTIsMiddleMouse;
+	KEY			mPTTKey;
+	bool		mPTTIsToggle;
+	bool		mUserPTTState;
+	bool		mMuteMic;
+	bool		mDisableMic;
 };
 
 /**
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index e674fec053..3cdbe04fae 100644
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -44,7 +44,6 @@
 #include "llviewernetwork.h"		// for gGridChoice
 #include "llbase64.h"
 #include "llviewercontrol.h"
-#include "llkeyboard.h"
 #include "llappviewer.h"	// for gDisconnected, gDisableVoice
 #include "llmutelist.h"  // to check for muted avatars
 #include "llagent.h"
@@ -322,14 +321,8 @@ LLVivoxVoiceClient::LLVivoxVoiceClient() :
 	mRenderDeviceDirty(false),
 	mSpatialCoordsDirty(false),
 
-	mPTTDirty(true),
-	mPTT(true),
-	mUsePTT(true),
-	mPTTIsMiddleMouse(false),
-	mPTTKey(0),
-	mPTTIsToggle(false),
-	mUserPTTState(false),
 	mMuteMic(false),
+	mMuteMicDirty(false),
 	mFriendsListDirty(true),
 
 	mEarLocation(0),
@@ -431,10 +424,6 @@ const LLVoiceVersionInfo& LLVivoxVoiceClient::getVersion()
 void LLVivoxVoiceClient::updateSettings()
 {
 	setVoiceEnabled(gSavedSettings.getBOOL("EnableVoiceChat"));
-	setUsePTT(gSavedSettings.getBOOL("PTTCurrentlyEnabled"));
-	std::string keyString = gSavedSettings.getString("PushToTalkButton");
-	setPTTKey(keyString);
-	setPTTIsToggle(gSavedSettings.getBOOL("PushToTalkToggle"));
 	setEarLocation(gSavedSettings.getS32("VoiceEarLocation"));
 
 	std::string inputDevice = gSavedSettings.getString("VoiceInputAudioDevice");
@@ -946,7 +935,7 @@ void LLVivoxVoiceClient::stateMachine()
 				setState(stateDaemonLaunched);
 				
 				// Dirty the states we'll need to sync with the daemon when it comes up.
-				mPTTDirty = true;
+				mMuteMicDirty = true;
 				mMicVolumeDirty = true;
 				mSpeakerVolumeDirty = true;
 				mSpeakerMuteDirty = true;
@@ -1531,7 +1520,7 @@ void LLVivoxVoiceClient::stateMachine()
 			if(mAudioSession && mAudioSession->mVoiceEnabled)
 			{
 				// Dirty state that may need to be sync'ed with the daemon.
-				mPTTDirty = true;
+				mMuteMicDirty = true;
 				mSpeakerVolumeDirty = true;
 				mSpatialCoordsDirty = true;
 				
@@ -1572,35 +1561,6 @@ void LLVivoxVoiceClient::stateMachine()
 			}
 			else
 			{
-				
-				// Figure out whether the PTT state needs to change
-				{
-					bool newPTT;
-					if(mUsePTT)
-					{
-						// If configured to use PTT, track the user state.
-						newPTT = mUserPTTState;
-					}
-					else
-					{
-						// If not configured to use PTT, it should always be true (otherwise the user will be unable to speak).
-						newPTT = true;
-					}
-					
-					if(mMuteMic)
-					{
-						// This always overrides any other PTT setting.
-						newPTT = false;
-					}
-					
-					// Dirty if state changed.
-					if(newPTT != mPTT)
-					{
-						mPTT = newPTT;
-						mPTTDirty = true;
-					}
-				}
-				
 				if(!inSpatialChannel())
 				{
 					// When in a non-spatial channel, never send positional updates.
@@ -1622,7 +1582,7 @@ void LLVivoxVoiceClient::stateMachine()
 				// Send an update only if the ptt or mute state has changed (which shouldn't be able to happen that often
 				// -- the user can only click so fast) or every 10hz, whichever is sooner.
 				// Sending for every volume update causes an excessive flood of messages whenever a volume slider is dragged.
-				if((mAudioSession && mAudioSession->mMuteDirty) || mPTTDirty || mUpdateTimer.hasExpired())
+				if((mAudioSession && mAudioSession->mMuteDirty) || mMuteMicDirty || mUpdateTimer.hasExpired())
 				{
 					mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS);
 					sendPositionalUpdate();
@@ -2745,19 +2705,17 @@ void LLVivoxVoiceClient::buildLocalAudioUpdates(std::ostringstream &stream)
 
 	buildSetRenderDevice(stream);
 
-	if(mPTTDirty)
+	if(mMuteMicDirty)
 	{
-		mPTTDirty = false;
+		mMuteMicDirty = false;
 
 		// Send a local mute command.
-		// NOTE that the state of "PTT" is the inverse of "local mute".
-		//   (i.e. when PTT is true, we send a mute command with "false", and vice versa)
 		
-		LL_DEBUGS("Voice") << "Sending MuteLocalMic command with parameter " << (mPTT?"false":"true") << LL_ENDL;
+		LL_DEBUGS("Voice") << "Sending MuteLocalMic command with parameter " << (mMuteMic?"true":"false") << LL_ENDL;
 
 		stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalMic.1\">"
 			<< "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
-			<< "<Value>" << (mPTT?"false":"true") << "</Value>"
+			<< "<Value>" << (mMuteMic?"true":"false") << "</Value>"
 			<< "</Request>\n\n\n";
 		
 	}
@@ -5230,40 +5188,13 @@ void LLVivoxVoiceClient::leaveChannel(void)
 
 void LLVivoxVoiceClient::setMuteMic(bool muted)
 {
-	mMuteMic = muted;
-}
-
-void LLVivoxVoiceClient::setUserPTTState(bool ptt)
-{
-	mUserPTTState = ptt;
-}
-
-bool LLVivoxVoiceClient::getUserPTTState()
-{
-	return mUserPTTState;
-}
-
-void LLVivoxVoiceClient::inputUserControlState(bool down)
-{
-	if(mPTTIsToggle)
+	if(mMuteMic != muted)
 	{
-		if(down) // toggle open-mic state on 'down'                                                        
-		{
-			toggleUserPTTState();
-		}
-	}
-	else // set open-mic state as an absolute                                                                  
-	{
-		setUserPTTState(down);
+		mMuteMic = muted;
+		mMuteMicDirty = true;
 	}
 }
 
-
-void LLVivoxVoiceClient::toggleUserPTTState(void)
-{
-	mUserPTTState = !mUserPTTState;
-}
-
 void LLVivoxVoiceClient::setVoiceEnabled(bool enabled)
 {
 	if (enabled != mVoiceEnabled)
@@ -5312,48 +5243,6 @@ BOOL LLVivoxVoiceClient::lipSyncEnabled()
 	}
 }
 
-void LLVivoxVoiceClient::setUsePTT(bool usePTT)
-{
-	if(usePTT && !mUsePTT)
-	{
-		// When the user turns on PTT, reset the current state.
-		mUserPTTState = false;
-	}
-	mUsePTT = usePTT;
-}
-
-void LLVivoxVoiceClient::setPTTIsToggle(bool PTTIsToggle)
-{
-	if(!PTTIsToggle && mPTTIsToggle)
-	{
-		// When the user turns off toggle, reset the current state.
-		mUserPTTState = false;
-	}
-	
-	mPTTIsToggle = PTTIsToggle;
-}
-
-bool LLVivoxVoiceClient::getPTTIsToggle()
-{
-	return mPTTIsToggle;
-}
-
-void LLVivoxVoiceClient::setPTTKey(std::string &key)
-{
-	if(key == "MiddleMouse")
-	{
-		mPTTIsMiddleMouse = true;
-	}
-	else
-	{
-		mPTTIsMiddleMouse = false;
-		if(!LLKeyboard::keyFromString(key, &mPTTKey))
-		{
-			// If the call failed, don't match any key.
-			key = KEY_NONE;
-		}
-	}
-}
 
 void LLVivoxVoiceClient::setEarLocation(S32 loc)
 {
@@ -5394,44 +5283,6 @@ void LLVivoxVoiceClient::setMicGain(F32 volume)
 	}
 }
 
-void LLVivoxVoiceClient::keyDown(KEY key, MASK mask)
-{	
-	if (gKeyboard->getKeyRepeated(key))
-	{
-		// ignore auto-repeat keys                                                                         
-		return;
-	}
-	
-	if(!mPTTIsMiddleMouse)
-	{
-		bool down = (mPTTKey != KEY_NONE)
-		&& gKeyboard->getKeyDown(mPTTKey);
-		inputUserControlState(down);
-	}
-	
-	
-}
-void LLVivoxVoiceClient::keyUp(KEY key, MASK mask)
-{
-	if(!mPTTIsMiddleMouse)
-	{
-		bool down = (mPTTKey != KEY_NONE)
-		&& gKeyboard->getKeyDown(mPTTKey);
-		inputUserControlState(down);
-	}
-	
-}
-void LLVivoxVoiceClient::middleMouseState(bool down)
-{
-	if(mPTTIsMiddleMouse)
-	{
-        if(mPTTIsMiddleMouse)
-        {
-			inputUserControlState(down);
-        }		
-	}
-}
-
 /////////////////////////////
 // Accessors for data related to nearby speakers
 BOOL LLVivoxVoiceClient::getVoiceEnabled(const LLUUID& id)
@@ -7005,8 +6856,8 @@ void LLVivoxVoiceClient::captureBufferRecordStartSendMessage()
 			<< "<Value>false</Value>"
 		<< "</Request>\n\n\n";
 
-		// Dirty the PTT state so that it will get reset when we finishing previewing
-		mPTTDirty = true;
+		// Dirty the mute mic state so that it will get reset when we finishing previewing
+		mMuteMicDirty = true;
 
 		writeString(stream.str());
 	}
@@ -7020,7 +6871,7 @@ void LLVivoxVoiceClient::captureBufferRecordStopSendMessage()
 
 		LL_DEBUGS("Voice") << "Stopping audio capture to buffer." << LL_ENDL;
 
-		// Mute the mic. PTT state was dirtied at recording start, so will be reset when finished previewing.
+		// Mute the mic. Mic mute state was dirtied at recording start, so will be reset when finished previewing.
 		stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalMic.1\">"
 			<< "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>"
 			<< "<Value>true</Value>"
diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h
index 08f2f75a39..04ac35ff82 100644
--- a/indra/newview/llvoicevivox.h
+++ b/indra/newview/llvoicevivox.h
@@ -173,25 +173,9 @@ public:
 	virtual void setVoiceEnabled(bool enabled);
 	virtual BOOL lipSyncEnabled();	
 	virtual void setLipSyncEnabled(BOOL enabled);
-	virtual void setMuteMic(bool muted);		// Use this to mute the local mic (for when the client is minimized, etc), ignoring user PTT state.
+	virtual void setMuteMic(bool muted);		// Set the mute state of the local mic.
 	//@}
-	
-	////////////////////////
-	/// @name PTT
-	//@{
-	virtual void setUserPTTState(bool ptt);
-	virtual bool getUserPTTState();
-	virtual void setUsePTT(bool usePTT);
-	virtual void setPTTIsToggle(bool PTTIsToggle);
-	virtual bool getPTTIsToggle();
-	virtual void inputUserControlState(bool down);  // interpret any sort of up-down mic-open control input according to ptt-toggle prefs	
-	virtual void toggleUserPTTState(void);
-	
-	virtual void keyDown(KEY key, MASK mask);
-	virtual void keyUp(KEY key, MASK mask);
-	virtual void middleMouseState(bool down);
-	//@}
-	
+		
 	//////////////////////////
 	/// @name nearby speaker accessors
 	//@{
@@ -534,9 +518,6 @@ protected:
 										// Use this to determine whether to show a "no speech" icon in the menu bar.
 		
 	
-	// PTT
-	void setPTTKey(std::string &key);
-	
 	/////////////////////////////
 	// Recording controls
 	void recordingLoopStart(int seconds = 3600, int deltaFramesPerControlFrame = 200);
@@ -800,15 +781,8 @@ private:
 	LLVector3	mAvatarVelocity;
 	LLMatrix3	mAvatarRot;
 	
-	bool		mPTTDirty;
-	bool		mPTT;
-	
-	bool		mUsePTT;
-	bool		mPTTIsMiddleMouse;
-	KEY			mPTTKey;
-	bool		mPTTIsToggle;
-	bool		mUserPTTState;
 	bool		mMuteMic;
+	bool		mMuteMicDirty;
 			
 	// Set to true when the friends list is known to have changed.
 	bool		mFriendsListDirty;
-- 
cgit v1.2.3


From 08017d0af830e925ed73dd39e89d2a24d474b499 Mon Sep 17 00:00:00 2001
From: callum <none@none>
Date: Mon, 27 Sep 2010 16:33:17 -0700
Subject: Addenum to EXP-94 Disable local file system access - also handle dir
 picker selection too

---
 indra/newview/lldirpicker.cpp | 40 +++++++++++++++++++++++++++++++++++++++-
 indra/newview/lldirpicker.h   |  1 +
 2 files changed, 40 insertions(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/lldirpicker.cpp b/indra/newview/lldirpicker.cpp
index 53101f0ce2..dd243397a1 100644
--- a/indra/newview/lldirpicker.cpp
+++ b/indra/newview/lldirpicker.cpp
@@ -35,6 +35,7 @@
 #include "llframetimer.h"
 #include "lltrans.h"
 #include "llwindow.h"	// beforeDialog()
+#include "llviewercontrol.h"
 
 #if LL_LINUX || LL_SOLARIS
 # include "llfilepicker.h"
@@ -53,6 +54,23 @@ LLDirPicker LLDirPicker::sInstance;
 //
 // Implementation
 //
+
+// utility function to check if access to local file system via file browser 
+// is enabled and if not, tidy up and indicate we're not allowed to do this.
+bool LLDirPicker::check_local_file_access_enabled()
+{
+	// if local file browsing is turned off, return without opening dialog
+	bool local_file_system_browsing_enabled = gSavedSettings.getBOOL("LocalFileSystemBrowsingEnabled");
+	if ( ! local_file_system_browsing_enabled )
+	{
+		mDir.clear();	// Windows
+		mFileName = NULL; // Mac/Linux
+		return false;
+	}
+
+	return true;
+}
+
 #if LL_WINDOWS
 
 LLDirPicker::LLDirPicker() :
@@ -72,6 +90,13 @@ BOOL LLDirPicker::getDir(std::string* filename)
 	{
 		return FALSE;
 	}
+
+	// if local file browsing is turned off, return without opening dialog
+	if ( check_local_file_access_enabled() == false )
+	{
+		return FALSE;
+	}
+
 	BOOL success = FALSE;
 
 	// Modal, so pause agent
@@ -231,7 +256,13 @@ BOOL LLDirPicker::getDir(std::string* filename)
 	if( mLocked ) return FALSE;
 	BOOL success = FALSE;
 	OSStatus	error = noErr;
-	
+
+	// if local file browsing is turned off, return without opening dialog
+	if ( check_local_file_access_enabled() == false )
+	{
+		return FALSE;
+	}
+
 	mFileName = filename;
 	
 //	mNavOptions.saveFileName 
@@ -289,6 +320,13 @@ void LLDirPicker::reset()
 BOOL LLDirPicker::getDir(std::string* filename)
 {
 	reset();
+
+	// if local file browsing is turned off, return without opening dialog
+	if ( check_local_file_access_enabled() == false )
+	{
+		return FALSE;
+	}
+
 	if (mFilePicker)
 	{
 		GtkWindow* picker = mFilePicker->buildFilePicker(false, true,
diff --git a/indra/newview/lldirpicker.h b/indra/newview/lldirpicker.h
index a360293fff..2188b7edd0 100644
--- a/indra/newview/lldirpicker.h
+++ b/indra/newview/lldirpicker.h
@@ -75,6 +75,7 @@ private:
 	};
 	
 	void buildDirname( void );
+	bool check_local_file_access_enabled();
 
 #if LL_DARWIN
 	NavDialogCreationOptions mNavOptions;
-- 
cgit v1.2.3


From 594a115c92a84c90d1dbcc393b2ee7a189644f5f Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Tue, 28 Sep 2010 14:55:49 -0700
Subject: removed minimal skin in favor of user folder approach

---
 indra/newview/skins/minimal/xui/en/main_view.xml | 27 ------------------------
 1 file changed, 27 deletions(-)
 delete mode 100644 indra/newview/skins/minimal/xui/en/main_view.xml

(limited to 'indra/newview')

diff --git a/indra/newview/skins/minimal/xui/en/main_view.xml b/indra/newview/skins/minimal/xui/en/main_view.xml
deleted file mode 100644
index c793b1b813..0000000000
--- a/indra/newview/skins/minimal/xui/en/main_view.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<panel
- follows="left|right|top|bottom"
- height="768"
- layout="topleft"
- left="0"
- mouse_opaque="false"
- tab_stop="false" 
- name="main_view"
- width="1024">
-  <view top="0"
-        follows="all"
-        height="768"
-        left="0"
-        mouse_opaque="false"
-        name="world_view_rect"
-        width="1024"/>
-  <panel top="0"
-         follows="all"
-         height="768"
-         mouse_opaque="true"
-         name="progress_view"
-         filename="panel_progress.xml"
-         class="progress_view"
-         width="1024"
-         visible="false"/>
-</panel>
-- 
cgit v1.2.3


From ff071bbdce6478f8cd666ecf75658ca6e24f1140 Mon Sep 17 00:00:00 2001
From: Monroe Linden <monroe@lindenlab.com>
Date: Tue, 28 Sep 2010 16:49:22 -0700
Subject: Added a mechanism for preventing classes of notifications from being
 displayed, controlled by the notification_visibility.xml file in the viewer
 skin.

Reviewed by Richard.
---
 indra/newview/llfloaternotificationsconsole.cpp                | 1 +
 indra/newview/skins/default/xui/en/notification_visibility.xml | 5 +++++
 2 files changed, 6 insertions(+)
 create mode 100644 indra/newview/skins/default/xui/en/notification_visibility.xml

(limited to 'indra/newview')

diff --git a/indra/newview/llfloaternotificationsconsole.cpp b/indra/newview/llfloaternotificationsconsole.cpp
index 42dc60f9e0..29af81d64c 100644
--- a/indra/newview/llfloaternotificationsconsole.cpp
+++ b/indra/newview/llfloaternotificationsconsole.cpp
@@ -174,6 +174,7 @@ BOOL LLFloaterNotificationConsole::postBuild()
 	// these are in the order of processing
 	addChannel("Unexpired");
 	addChannel("Ignore");
+	addChannel("VisibilityRules");
 	addChannel("Visible", true);
 	// all the ones below attach to the Visible channel
 	addChannel("Persistent");
diff --git a/indra/newview/skins/default/xui/en/notification_visibility.xml b/indra/newview/skins/default/xui/en/notification_visibility.xml
new file mode 100644
index 0000000000..cb36890fe6
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/notification_visibility.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" ?>
+<notification_visibility>
+	<rule visible="true"/> 
+</notification_visibility>
+
-- 
cgit v1.2.3


From 95ecad54c6f037910a5a22f7ef30026cf628fe80 Mon Sep 17 00:00:00 2001
From: callum <none@none>
Date: Tue, 28 Sep 2010 16:52:56 -0700
Subject: EXP-112 Enable fullscreen mode (with mode switch, not resize to
 desktop) as per 1.x viewer.

---
 indra/newview/app_settings/cmd_line.xml |  8 ++++++++
 indra/newview/app_settings/settings.xml | 11 +++++++++++
 indra/newview/llappviewer.cpp           |  2 +-
 indra/newview/llviewerwindow.cpp        | 11 ++++++++++-
 4 files changed, 30 insertions(+), 2 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/cmd_line.xml b/indra/newview/app_settings/cmd_line.xml
index 962c4e9d36..aa2f1c41d2 100644
--- a/indra/newview/app_settings/cmd_line.xml
+++ b/indra/newview/app_settings/cmd_line.xml
@@ -391,5 +391,13 @@
       <string>CrashOnStartup</string>
     </map>
 
+    <key>fullscreen</key>
+    <map>
+      <key>desc</key>
+      <string>Force full screen mode</string>
+      <key>map-to</key>
+      <string>WindowFullScreen</string>
+    </map>
+
   </map>
 </llsd>
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index a83291b530..9c19d2c638 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -11684,6 +11684,17 @@
       <string>Boolean</string>
       <key>Value</key>
       <integer>1</integer>
+    </map> 
+    <key>WindowFullScreen</key>
+    <map>
+      <key>Comment</key>
+      <string>SL viewer window full screen</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
     </map>
     <key>WindowHeight</key>
     <map>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 02a8c3e674..956f67df86 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2386,7 +2386,7 @@ bool LLAppViewer::initWindow()
 		VIEWER_WINDOW_CLASSNAME,
 		gSavedSettings.getS32("WindowX"), gSavedSettings.getS32("WindowY"),
 		gSavedSettings.getS32("WindowWidth"), gSavedSettings.getS32("WindowHeight"),
-		FALSE, ignorePixelDepth);
+		gSavedSettings.getBOOL("WindowFullScreen"), ignorePixelDepth);
 
 	// Need to load feature table before cheking to start watchdog.
 	const S32 NEVER_SUBMIT_REPORT = 2;
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index fb43b51deb..ea32adf5b6 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1349,8 +1349,17 @@ LLViewerWindow::LLViewerWindow(
 	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)
 	{
-- 
cgit v1.2.3


From 67be46c78a28864360a0ca5ba66d6044a1b9b38d Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Tue, 28 Sep 2010 17:12:50 -0700
Subject: made mIsFocusRoot a XUI param

---
 indra/newview/llnavigationbar.cpp                            | 3 ---
 indra/newview/llpanellogin.cpp                               | 2 --
 indra/newview/llsidetray.cpp                                 | 2 --
 indra/newview/skins/default/xui/en/panel_bottomtray.xml      | 1 +
 indra/newview/skins/default/xui/en/panel_bottomtray_lite.xml | 1 +
 indra/newview/skins/default/xui/en/panel_login.xml           | 1 +
 indra/newview/skins/default/xui/en/panel_navigation_bar.xml  | 1 +
 indra/newview/skins/default/xui/en/widgets/sidetray_tab.xml  | 4 ++++
 8 files changed, 8 insertions(+), 7 deletions(-)
 create mode 100644 indra/newview/skins/default/xui/en/widgets/sidetray_tab.xml

(limited to 'indra/newview')

diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp
index 58849393b4..e4f83ce6b9 100644
--- a/indra/newview/llnavigationbar.cpp
+++ b/indra/newview/llnavigationbar.cpp
@@ -276,9 +276,6 @@ LLNavigationBar::LLNavigationBar()
 
 	// set a listener function for LoginComplete event
 	LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLNavigationBar::handleLoginComplete, this));
-
-	// Necessary for focus movement among child controls
-	setFocusRoot(TRUE);
 }
 
 LLNavigationBar::~LLNavigationBar()
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index 7c93d8a1f9..2f3e0875b8 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -163,8 +163,6 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
 	mHtmlAvailable( TRUE ),
 	mListener(new LLPanelLoginListener(this))
 {
-	setFocusRoot(TRUE);
-
 	setBackgroundVisible(FALSE);
 	setBackgroundOpaque(TRUE);
 
diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp
index 521e5005e8..53d8a5c19e 100644
--- a/indra/newview/llsidetray.cpp
+++ b/indra/newview/llsidetray.cpp
@@ -155,8 +155,6 @@ LLSideTrayTab::LLSideTrayTab(const Params& p)
 	mDescription(p.description),
 	mMainPanel(NULL)
 {
-	// Necessary for focus movement among child controls
-	setFocusRoot(TRUE);
 }
 
 LLSideTrayTab::~LLSideTrayTab()
diff --git a/indra/newview/skins/default/xui/en/panel_bottomtray.xml b/indra/newview/skins/default/xui/en/panel_bottomtray.xml
index 63068a069f..013a8090f7 100644
--- a/indra/newview/skins/default/xui/en/panel_bottomtray.xml
+++ b/indra/newview/skins/default/xui/en/panel_bottomtray.xml
@@ -5,6 +5,7 @@
  bg_opaque_color="DkGray"
  chrome="true"
  follows="left|bottom|right"
+ focus_root="true" 
  height="33"
  layout="topleft"
  left="0"
diff --git a/indra/newview/skins/default/xui/en/panel_bottomtray_lite.xml b/indra/newview/skins/default/xui/en/panel_bottomtray_lite.xml
index efb1da4c05..b5e1a5f16d 100644
--- a/indra/newview/skins/default/xui/en/panel_bottomtray_lite.xml
+++ b/indra/newview/skins/default/xui/en/panel_bottomtray_lite.xml
@@ -10,6 +10,7 @@
  layout="topleft"
  left="0"
  name="bottom_tray_lite"
+ focus_root="true" 
  tab_stop="true"
  top="28"
  chrome="true"
diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml
index 891616b838..321e6c4cda 100644
--- a/indra/newview/skins/default/xui/en/panel_login.xml
+++ b/indra/newview/skins/default/xui/en/panel_login.xml
@@ -5,6 +5,7 @@ height="600"
 layout="topleft"
 left="0"
 name="panel_login"
+focus_root="true" 
 top="600"
  width="996">
 <panel.string
diff --git a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml
index 082d51ed3c..8a7bd53054 100644
--- a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml
+++ b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml
@@ -4,6 +4,7 @@
  background_visible="true"
  bg_opaque_color="MouseGray"
  follows="left|top|right"
+ focus_root="true" 
  height="60"
  layout="topleft"
  name="navigation_bar"
diff --git a/indra/newview/skins/default/xui/en/widgets/sidetray_tab.xml b/indra/newview/skins/default/xui/en/widgets/sidetray_tab.xml
new file mode 100644
index 0000000000..aa8461d367
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/widgets/sidetray_tab.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<sidetray_tab 
+  focus_root="true"
+  />
-- 
cgit v1.2.3


From 6c1f89ea6e0d63c59da4e3a33c9252371032b58b Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Tue, 28 Sep 2010 17:13:08 -0700
Subject: added settings to toggle grab and alt-zoom ability

---
 indra/newview/app_settings/settings.xml | 22 ++++++++++++++++++++++
 indra/newview/lltool.cpp                |  8 ++++++--
 indra/newview/lltoolpie.cpp             | 16 +++++++++-------
 3 files changed, 37 insertions(+), 9 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index a83291b530..13fed89867 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -2820,6 +2820,28 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
+    <key>EnableGrab</key>
+    <map>
+      <key>Comment</key>
+      <string>Use Ctrl+mouse to grab and manipulate objects</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
+    <key>EnableAltZoom</key>
+    <map>
+      <key>Comment</key>
+      <string>Use Alt+mouse to look at and zoom in on objects</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
     <key>EnableRippleWater</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/lltool.cpp b/indra/newview/lltool.cpp
index 282d4e19c6..2d8ce95347 100644
--- a/indra/newview/lltool.cpp
+++ b/indra/newview/lltool.cpp
@@ -33,6 +33,7 @@
 #include "llview.h"
 
 #include "llviewerwindow.h"
+#include "llviewercontrol.h"
 #include "lltoolcomp.h"
 #include "lltoolfocus.h"
 #include "llfocusmgr.h"
@@ -190,9 +191,12 @@ LLTool* LLTool::getOverrideTool(MASK mask)
 	{
 		return NULL;
 	}
-	if (mask & MASK_ALT)
+	if (gSavedSettings.getBOOL("EnableAltZoom"))
 	{
-		return LLToolCamera::getInstance();
+		if (mask & MASK_ALT)
+		{
+			return LLToolCamera::getInstance();
+		}
 	}
 	return NULL;
 }
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index 864de018e0..2ee3e4ffed 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -1210,15 +1210,17 @@ void LLToolPie::handleDeselect()
 
 LLTool* LLToolPie::getOverrideTool(MASK mask)
 {
-	if (mask == MASK_CONTROL)
+	if (gSavedSettings.getBOOL("EnableGrab"))
 	{
-		return LLToolGrab::getInstance();
-	}
-	else if (mask == (MASK_CONTROL | MASK_SHIFT))
-	{
-		return LLToolGrab::getInstance();
+		if (mask == MASK_CONTROL)
+		{
+			return LLToolGrab::getInstance();
+		}
+		else if (mask == (MASK_CONTROL | MASK_SHIFT))
+		{
+			return LLToolGrab::getInstance();
+		}
 	}
-
 	return LLTool::getOverrideTool(mask);
 }
 
-- 
cgit v1.2.3


From ebb492089498450d858126bce35fecf09e62324d Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Tue, 28 Sep 2010 17:13:24 -0700
Subject: added xui param to turn off drag-and-drop reordering of bottom tray
 buttons

---
 indra/newview/llbottomtray.cpp | 52 +++++++++++++++++++++++-------------------
 indra/newview/llbottomtray.h   |  9 ++++++--
 2 files changed, 35 insertions(+), 26 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp
index 33d006578d..b5fa198bae 100644
--- a/indra/newview/llbottomtray.cpp
+++ b/indra/newview/llbottomtray.cpp
@@ -65,31 +65,42 @@ LLDefaultChildRegistry::Register<LLBottomtrayButton> bottomtray_button("bottomtr
 // virtual
 BOOL LLBottomtrayButton::handleHover(S32 x, S32 y, MASK mask)
 {
-	S32 screenX, screenY;
-	localPointToScreen(x, y, &screenX, &screenY);
-	// pass hover to bottomtray
-	LLBottomTray::getInstance()->onDraggableButtonHover(screenX, screenY);
-	return FALSE;
+	if (mCanDrag)
+	{
+		S32 screenX, screenY;
+		localPointToScreen(x, y, &screenX, &screenY);
+		// pass hover to bottomtray
+		LLBottomTray::getInstance()->onDraggableButtonHover(screenX, screenY);
+		return TRUE;
+	}
+	else
+	{
+		return LLButton::handleHover(x, y, mask);
+	}
 }
 //virtual
 BOOL LLBottomtrayButton::handleMouseUp(S32 x, S32 y, MASK mask)
 {
-	S32 screenX, screenY;
-	localPointToScreen(x, y, &screenX, &screenY);
-	// pass mouse up to bottomtray
-	LLBottomTray::getInstance()->onDraggableButtonMouseUp(this, screenX, screenY);
-	LLButton::handleMouseUp(x, y, mask);
-	return FALSE;
+	if (mCanDrag)
+	{
+		S32 screenX, screenY;
+		localPointToScreen(x, y, &screenX, &screenY);
+		// pass mouse up to bottomtray
+		LLBottomTray::getInstance()->onDraggableButtonMouseUp(this, screenX, screenY);
+	}
+	return LLButton::handleMouseUp(x, y, mask);
 }
 //virtual
 BOOL LLBottomtrayButton::handleMouseDown(S32 x, S32 y, MASK mask)
 {
-	S32 screenX, screenY;
-	localPointToScreen(x, y, &screenX, &screenY);
-	// pass mouse up to bottomtray
-	LLBottomTray::getInstance()->onDraggableButtonMouseDown(this, screenX, screenY);
-	LLButton::handleMouseDown(x, y, mask);
-	return FALSE;
+	if (mCanDrag)
+	{
+		S32 screenX, screenY;
+		localPointToScreen(x, y, &screenX, &screenY);
+		// pass mouse up to bottomtray
+		LLBottomTray::getInstance()->onDraggableButtonMouseDown(this, screenX, screenY);
+	}
+	return LLButton::handleMouseDown(x, y, mask);
 }
 
 static void update_build_button_enable_state()
@@ -150,8 +161,6 @@ public:
 	{
 		mFactoryMap["chat_bar"] = LLCallbackMap(LLBottomTray::createNearbyChatBar, NULL);
 		buildFromFile("panel_bottomtray_lite.xml");
-		// Necessary for focus movement among child controls
-		setFocusRoot(TRUE);
 	}
 
 	BOOL postBuild()
@@ -211,16 +220,11 @@ LLBottomTray::LLBottomTray(const LLSD&)
 
 	buildFromFile("panel_bottomtray.xml");
 
-	LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("CameraPresets.ChangeView", boost::bind(&LLFloaterCamera::onClickCameraItem, _2));
-
 	//this is to fix a crash that occurs because LLBottomTray is a singleton
 	//and thus is deleted at the end of the viewers lifetime, but to be cleanly
 	//destroyed LLBottomTray requires some subsystems that are long gone
 	//LLUI::getRootView()->addChild(this);
 
-	// Necessary for focus movement among child controls
-	setFocusRoot(TRUE);
-
 	{
 		mBottomTrayLite = new LLBottomTrayLite();
 		mBottomTrayLite->setFollowsAll();
diff --git a/indra/newview/llbottomtray.h b/indra/newview/llbottomtray.h
index 8d8a42c553..dc98170049 100644
--- a/indra/newview/llbottomtray.h
+++ b/indra/newview/llbottomtray.h
@@ -54,7 +54,9 @@ class LLBottomtrayButton : public LLButton
 public:
 	struct Params : public LLInitParam::Block<Params, LLButton::Params>
 	{
-		Params(){}
+		Optional<bool> can_drag;
+		Params()
+		: can_drag("can_drag", true){}
 	};
 	/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
 	/*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask);
@@ -62,11 +64,14 @@ public:
 
 protected:
 	LLBottomtrayButton(const Params& p)
-		:	LLButton(p)
+	:	LLButton(p),
+		mCanDrag(p.can_drag)
 	{
 
 	}
 	friend class LLUICtrlFactory;
+
+	bool mCanDrag;
 };
 
 class LLBottomTray 
-- 
cgit v1.2.3


From 51ad14db881a68722530d54b5ac799a49f11264b Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Tue, 28 Sep 2010 17:13:50 -0700
Subject: moved callback registration to class that implements it

---
 indra/newview/llfloatercamera.cpp | 3 +++
 1 file changed, 3 insertions(+)

(limited to 'indra/newview')

diff --git a/indra/newview/llfloatercamera.cpp b/indra/newview/llfloatercamera.cpp
index ad24c6534a..b4e211a38e 100644
--- a/indra/newview/llfloatercamera.cpp
+++ b/indra/newview/llfloatercamera.cpp
@@ -336,6 +336,9 @@ LLFloaterCamera::LLFloaterCamera(const LLSD& val)
 	mCurrMode(CAMERA_CTRL_MODE_PAN),
 	mPrevMode(CAMERA_CTRL_MODE_PAN)
 {
+	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+	registrar.add("CameraPresets.ChangeView", boost::bind(&LLFloaterCamera::onClickCameraItem, _2));
+
 }
 
 // virtual
-- 
cgit v1.2.3


From 2fd5b397ad886d7f8a8792382374cd8c678abc0d Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Wed, 29 Sep 2010 15:11:39 -0700
Subject: turn off get more and view all options in gesture combo list

---
 indra/newview/llnearbychatbar.cpp | 30 +++++++++++++++++++-----------
 indra/newview/llnearbychatbar.h   |  4 ++++
 2 files changed, 23 insertions(+), 11 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llnearbychatbar.cpp b/indra/newview/llnearbychatbar.cpp
index 932ad75f29..836ae9a0cf 100644
--- a/indra/newview/llnearbychatbar.cpp
+++ b/indra/newview/llnearbychatbar.cpp
@@ -94,15 +94,19 @@ public:
 
 LLGestureComboList::Params::Params()
 :	combo_button("combo_button"),
-	combo_list("combo_list")
+	combo_list("combo_list"),
+	get_more("get_more", true),
+	view_all("view_all", true)
 {
 }
 
 LLGestureComboList::LLGestureComboList(const LLGestureComboList::Params& p)
-:	LLUICtrl(p)
-	, mLabel(p.label)
-	, mViewAllItemIndex(0)
-	, mGetMoreItemIndex(0)
+:	LLUICtrl(p),
+	mLabel(p.label),
+	mViewAllItemIndex(-1),
+	mGetMoreItemIndex(-1),
+	mShowViewAll(p.view_all),
+	mShowGetMore(p.get_more)
 {
 	LLBottomtrayButton::Params button_params = p.combo_button;
 	button_params.follows.flags(FOLLOWS_LEFT|FOLLOWS_BOTTOM|FOLLOWS_RIGHT);
@@ -286,12 +290,16 @@ void LLGestureComboList::refreshGestures()
 	sortByName();
 
 	// store indices for Get More and View All items (idx is the index followed by the last added Gesture)
-	mGetMoreItemIndex = idx;
-	mViewAllItemIndex = idx + 1;
-
-	// add Get More and View All items at the bottom
-	mList->addSimpleElement(LLTrans::getString("GetMoreGestures"), ADD_BOTTOM, LLSD(mGetMoreItemIndex));
-	mList->addSimpleElement(LLTrans::getString("ViewAllGestures"), ADD_BOTTOM, LLSD(mViewAllItemIndex));
+	if (mShowGetMore)
+	{
+		mGetMoreItemIndex = idx;
+		mList->addSimpleElement(LLTrans::getString("GetMoreGestures"), ADD_BOTTOM, LLSD(mGetMoreItemIndex));
+	}
+	if (mShowViewAll)
+	{
+		mViewAllItemIndex = idx + 1;
+		mList->addSimpleElement(LLTrans::getString("ViewAllGestures"), ADD_BOTTOM, LLSD(mViewAllItemIndex));
+	}
 
 	// Insert label after sorting, at top, with separator below it
 	mList->addSeparator(ADD_TOP);	
diff --git a/indra/newview/llnearbychatbar.h b/indra/newview/llnearbychatbar.h
index cc905736fd..033d1dd5a2 100644
--- a/indra/newview/llnearbychatbar.h
+++ b/indra/newview/llnearbychatbar.h
@@ -46,6 +46,8 @@ public:
 	{
 		Optional<LLBottomtrayButton::Params>			combo_button;
 		Optional<LLScrollListCtrl::Params>	combo_list;
+		Optional<bool>						get_more,
+											view_all;
 		
 		Params();
 	};
@@ -56,6 +58,8 @@ protected:
 	LLGestureComboList(const Params&);
 	std::vector<LLMultiGesture*> mGestures;
 	std::string mLabel;
+	bool			mShowViewAll;
+	bool			mShowGetMore;
 	LLSD::Integer mViewAllItemIndex;
 	LLSD::Integer mGetMoreItemIndex;
 
-- 
cgit v1.2.3


From af4b2247005268dbf92f8bc6994c7048b1035454 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Wed, 29 Sep 2010 16:24:31 -0700
Subject: final fix for llcontextmenugl crash on exit

---
 indra/newview/lllistcontextmenu.cpp | 28 +++++++++++++---------------
 indra/newview/lllistcontextmenu.h   |  3 +--
 2 files changed, 14 insertions(+), 17 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/lllistcontextmenu.cpp b/indra/newview/lllistcontextmenu.cpp
index ea744072d2..6421ab42bf 100644
--- a/indra/newview/lllistcontextmenu.cpp
+++ b/indra/newview/lllistcontextmenu.cpp
@@ -36,7 +36,6 @@
 #include "llviewermenu.h" // for LLViewerMenuHolderGL
 
 LLListContextMenu::LLListContextMenu()
-:	mMenu(NULL)
 {
 }
 
@@ -51,23 +50,22 @@ LLListContextMenu::~LLListContextMenu()
 	// of mMenu has already been deleted except of using LLHandle. EXT-4762.
 	if (!mMenuHandle.isDead())
 	{
-		mMenu->die();
-		mMenu = NULL;
+		mMenuHandle.get()->die();
 	}
 }
 
 void LLListContextMenu::show(LLView* spawning_view, const uuid_vec_t& uuids, S32 x, S32 y)
 {
-	if (mMenu)
+	LLContextMenu* menup = mMenuHandle.get();
+	if (menup)
 	{
 		//preventing parent (menu holder) from deleting already "dead" context menus on exit
-		LLView* parent = mMenu->getParent();
+		LLView* parent = menup->getParent();
 		if (parent)
 		{
-			parent->removeChild(mMenu);
+			parent->removeChild(menup);
 		}
-		delete mMenu;
-		mMenu = NULL;
+		delete menup;
 		mUUIDs.clear();
 	}
 
@@ -79,23 +77,23 @@ void LLListContextMenu::show(LLView* spawning_view, const uuid_vec_t& uuids, S32
 	mUUIDs.resize(uuids.size());
 	std::copy(uuids.begin(), uuids.end(), mUUIDs.begin());
 
-	mMenu = createMenu();
-	if (!mMenu)
+	menup = createMenu();
+	if (!menup)
 	{
 		llwarns << "Context menu creation failed" << llendl;
 		return;
 	}
 
-	mMenuHandle = mMenu->getHandle();
-	mMenu->show(x, y);
-	LLMenuGL::showPopup(spawning_view, mMenu, x, y);
+	mMenuHandle = menup->getHandle();
+	menup->show(x, y);
+	LLMenuGL::showPopup(spawning_view, menup, x, y);
 }
 
 void LLListContextMenu::hide()
 {
-	if(mMenu)
+	if(mMenuHandle.get())
 	{
-		mMenu->hide();
+		mMenuHandle.get()->hide();
 	}
 }
 
diff --git a/indra/newview/lllistcontextmenu.h b/indra/newview/lllistcontextmenu.h
index 5dedc30b0c..fabd68ee20 100644
--- a/indra/newview/lllistcontextmenu.h
+++ b/indra/newview/lllistcontextmenu.h
@@ -71,8 +71,7 @@ protected:
 	static void handleMultiple(functor_t functor, const uuid_vec_t& ids);
 
 	uuid_vec_t			mUUIDs;
-	LLContextMenu*		mMenu;
-	LLHandle<LLView>	mMenuHandle;
+	LLHandle<LLContextMenu>	mMenuHandle;
 };
 
 #endif // LL_LLLISTCONTEXTMENU_H
-- 
cgit v1.2.3


From 6eb02995646e8c8dc91b68afde3e7f9b35aefac2 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Wed, 29 Sep 2010 17:39:44 -0700
Subject: login panel now properly nested in main_view.xml, no more z order
 hackery

---
 indra/newview/llpanellogin.cpp                   | 9 ++++++---
 indra/newview/llviewerwindow.cpp                 | 1 +
 indra/newview/llviewerwindow.h                   | 2 ++
 indra/newview/skins/default/xui/en/main_view.xml | 6 ++++++
 4 files changed, 15 insertions(+), 3 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index 2f3e0875b8..f348692e3d 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -179,8 +179,11 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
 	mPasswordModified = FALSE;
 	LLPanelLogin::sInstance = this;
 
-	// add to front so we are the bottom-most child
-	gViewerWindow->getRootView()->addChildInBack(this);
+	LLView* login_holder = gViewerWindow->getLoginPanelHolder();
+	if (login_holder)
+	{
+		login_holder->addChild(this);
+	}
 
 	// Logo
 	mLogoImage = LLUI::getUIImage("startup_logo");
@@ -737,7 +740,7 @@ void LLPanelLogin::closePanel()
 {
 	if (sInstance)
 	{
-		gViewerWindow->getRootView()->removeChild( LLPanelLogin::sInstance );
+		LLPanelLogin::sInstance->getParent()->removeChild( LLPanelLogin::sInstance );
 
 		delete sInstance;
 		sInstance = NULL;
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index ea32adf5b6..63d178457d 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1535,6 +1535,7 @@ void LLViewerWindow::initBase()
 	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");
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index 633c3a41d2..c944317933 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -288,6 +288,7 @@ public:
 	LLView*			getNonSideTrayView() { return mNonSideTrayView.get(); }
 	LLView*			getFloaterViewHolder() { return mFloaterViewHolder.get(); }
 	LLView*			getHintHolder() { return mHintHolder.get(); }
+	LLView*			getLoginPanelHolder() { return mLoginPanelHolder.get(); }
 	BOOL			handleKey(KEY key, MASK mask);
 	void			handleScrollWheel	(S32 clicks);
 
@@ -448,6 +449,7 @@ protected:
 	LLHandle<LLView> mNonSideTrayView;		// parent of world view + bottom bar, etc...everything but the side tray
 	LLHandle<LLView> mFloaterViewHolder;	// container for floater_view
 	LLHandle<LLView> mHintHolder;			// container for hints
+	LLHandle<LLView> mLoginPanelHolder;		// container for login panel
 	LLPopupView*	mPopupView;			// container for transient popups
 	
 	class LLDebugText* mDebugText; // Internal class for debug text
diff --git a/indra/newview/skins/default/xui/en/main_view.xml b/indra/newview/skins/default/xui/en/main_view.xml
index 8d9ebf6e06..a4f8b35c89 100644
--- a/indra/newview/skins/default/xui/en/main_view.xml
+++ b/indra/newview/skins/default/xui/en/main_view.xml
@@ -206,6 +206,12 @@
         name="hint_holder"
         mouse_opaque="false"
         follows="all"/>
+  <panel top="0"
+       follows="all"
+       height="768"
+       mouse_opaque="true"
+       name="login_panel_holder"
+       width="1024"/>
   <panel top="0"
          follows="all"
          height="768"
-- 
cgit v1.2.3


From 900d23ffe1faad8dab66761de7f125a616b6156f Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Wed, 29 Sep 2010 21:47:54 -0700
Subject: fix for clicks not working once logged in

---
 indra/newview/skins/default/xui/en/main_view.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/skins/default/xui/en/main_view.xml b/indra/newview/skins/default/xui/en/main_view.xml
index a4f8b35c89..71ca33a2d0 100644
--- a/indra/newview/skins/default/xui/en/main_view.xml
+++ b/indra/newview/skins/default/xui/en/main_view.xml
@@ -209,7 +209,7 @@
   <panel top="0"
        follows="all"
        height="768"
-       mouse_opaque="true"
+       mouse_opaque="false"
        name="login_panel_holder"
        width="1024"/>
   <panel top="0"
-- 
cgit v1.2.3


From 7934dd649ec0a06965cb540fa5e95adfc2ab3090 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Wed, 29 Sep 2010 21:52:45 -0700
Subject: added show inspector menu callbacks

---
 indra/newview/llviewermenu.cpp | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

(limited to 'indra/newview')

diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index d4af5048c3..07b6a9e642 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -190,6 +190,8 @@ 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);
@@ -4368,6 +4370,33 @@ void handle_take()
 	}
 }
 
+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);
@@ -8158,6 +8187,7 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLAvatarInviteToGroup(), "Avatar.InviteToGroup");
 	view_listener_t::addMenu(new LLAvatarGiveCard(), "Avatar.GiveCard");
 	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));
@@ -8185,6 +8215,7 @@ void initialize_menus()
 	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));
-- 
cgit v1.2.3


From 2b6d3b851fc6210e7cf6272ac0bc9f8645ca5644 Mon Sep 17 00:00:00 2001
From: Monroe Linden <monroe@lindenlab.com>
Date: Thu, 30 Sep 2010 14:48:36 -0700
Subject: Adding tags mechanism to notification visibility rules.

Also started adding the tag 'fail' to entries in notifications.xml that are failures the user should always be told about.

Reviewed by Richard.
---
 .../newview/skins/default/xui/en/notifications.xml | 23 ++++++++++++++++++++++
 1 file changed, 23 insertions(+)

(limited to 'indra/newview')

diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 5966db9d51..e36109caed 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -5046,6 +5046,7 @@ You can only claim public land in the Region you&apos;re in.
    name="RegionTPAccessBlocked"
    persist="true"
    type="notify">
+   <tag>fail</tag>
 You aren&apos;t allowed in that Region due to your maturity Rating. You may need to validate your age and/or install the latest Viewer.
 
 Please go to the Knowledge Base for details on accessing areas with this maturity Rating.
@@ -5056,6 +5057,7 @@ Please go to the Knowledge Base for details on accessing areas with this maturit
 	name="URBannedFromRegion"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 You are banned from the region.
   </notification>
 
@@ -5064,6 +5066,7 @@ You are banned from the region.
 	name="NoTeenGridAccess"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 Your account cannot connect to this teen grid region.
   </notification>
 
@@ -5072,6 +5075,7 @@ Your account cannot connect to this teen grid region.
 	name="ImproperPaymentStatus"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 You do not have proper payment status to enter this region.
   </notification>
 
@@ -5080,6 +5084,7 @@ You do not have proper payment status to enter this region.
 	name="MustGetAgeRgion"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 You must be age-verified to enter this region.
   </notification>
 
@@ -5088,6 +5093,7 @@ You must be age-verified to enter this region.
 	name="MustGetAgeParcel"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 You must be age-verified to enter this parcel.
   </notification>
 
@@ -5096,6 +5102,7 @@ You must be age-verified to enter this parcel.
 	name="NoDestRegion"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 No destination region found.
   </notification>
 
@@ -5104,6 +5111,7 @@ No destination region found.
 	name="NotAllowedInDest"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 You are not allowed into the destination.
   </notification>
 
@@ -5112,6 +5120,7 @@ You are not allowed into the destination.
 	name="RegionParcelBan"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 Cannot region cross into banned parcel. Try another way.
   </notification>
 
@@ -5128,6 +5137,7 @@ You have been redirected to a telehub.
 	name="CouldntTPCloser"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 Could not teleport closer to destination.
   </notification>
 
@@ -5144,6 +5154,7 @@ Teleport cancelled.
 	name="FullRegionTryAgain"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 The region you are attempting to enter is currently full.
 Please try again in a few moments.
   </notification>
@@ -5153,6 +5164,7 @@ Please try again in a few moments.
 	name="GeneralFailure"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 General failure.
   </notification>
 
@@ -5161,6 +5173,7 @@ General failure.
 	name="RoutedWrongRegion"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 Routed to wrong region. Please try again.
   </notification>
 
@@ -5169,6 +5182,7 @@ Routed to wrong region. Please try again.
 	name="NoValidAgentID"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 No valid agent id.
   </notification>
 
@@ -5177,6 +5191,7 @@ No valid agent id.
 	name="NoValidSession"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 No valid session id.
   </notification>
 
@@ -5185,6 +5200,7 @@ No valid session id.
 	name="NoValidCircuit"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 No valid circuit code.
   </notification>
 
@@ -5193,6 +5209,7 @@ No valid circuit code.
 	name="NoValidTimestamp"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 No valid timestamp.
   </notification>
 
@@ -5201,6 +5218,7 @@ No valid timestamp.
 	name="NoPendingConnection"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 Unable to create pending connection.
   </notification>
 
@@ -5209,6 +5227,7 @@ Unable to create pending connection.
 	name="InternalUsherError"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 Internal error attempting to connect agent usher.
   </notification>
 
@@ -5217,6 +5236,7 @@ Internal error attempting to connect agent usher.
 	name="NoGoodTPDestination"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 Unable to find a good teleport destination in this region.
   </notification>
 
@@ -5225,6 +5245,7 @@ Unable to find a good teleport destination in this region.
 	name="InternalErrorRegionResolver"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 Internal error attempting to activate region resolver.
   </notification>
 
@@ -5233,6 +5254,7 @@ Internal error attempting to activate region resolver.
 	name="NoValidLanding"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 A valid landing point could not be found.
   </notification>
 
@@ -5241,6 +5263,7 @@ A valid landing point could not be found.
 	name="NoValidParcel"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 No valid parcel could be found.
   </notification>
 
-- 
cgit v1.2.3


From c02f8c7eba89483b915864f9f914cac2cdfc8464 Mon Sep 17 00:00:00 2001
From: Monroe Linden <monroe@lindenlab.com>
Date: Thu, 30 Sep 2010 15:03:29 -0700
Subject: Added "win" tag to selected notifications.

---
 indra/newview/skins/default/xui/en/notifications.xml | 6 ++++++
 1 file changed, 6 insertions(+)

(limited to 'indra/newview')

diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index e36109caed..7dd7cefa5d 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -3118,6 +3118,7 @@ You have reached your maximum number of groups. Please leave some group before j
    icon="alert.tga"
    name="KickUser"
    type="alert">
+   <tag>win</tag>
 Kick this Resident with what message?
     <form name="form">
       <input name="message" type="text">
@@ -3139,6 +3140,7 @@ An administrator has logged you off.
    icon="alert.tga"
    name="KickAllUsers"
    type="alert">
+   <tag>win</tag>
 Kick everyone currently on the grid with what message?
     <form name="form">
       <input name="message" type="text">
@@ -3160,6 +3162,7 @@ An administrator has logged you off.
    icon="alert.tga"
    name="FreezeUser"
    type="alert">
+   <tag>win</tag>
 Freeze this Resident with what message?
     <form name="form">
       <input name="message" type="text">
@@ -3181,6 +3184,7 @@ You have been frozen. You cannot move or chat. An administrator will contact you
    icon="alert.tga"
    name="UnFreezeUser"
    type="alert">
+   <tag>win</tag>
 Unfreeze this Resident with what message?
     <form name="form">
       <input name="message" type="text">
@@ -5640,6 +5644,7 @@ Grant this request?
    name="FirstBalanceIncrease"
    persist="true"
    type="notify">
+   <tag>win</tag>
 You just received L$[AMOUNT].
 Your L$ balance is shown in the upper-right.
   </notification>
@@ -6118,6 +6123,7 @@ The SLurl you clicked on is not supported.
    name="BlockedSLURL"
    priority="high"
    type="notifytip">
+   <tag>win</tag>
 A SLurl was received from an untrusted browser and has been blocked for your security.
   </notification>
 
-- 
cgit v1.2.3


From 6b2f40b772f99d1f7c0b2e3779e612a076aa8f86 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Thu, 30 Sep 2010 15:17:32 -0700
Subject: fix for preferences window not visible on login

---
 indra/newview/skins/default/xui/en/main_view.xml | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/skins/default/xui/en/main_view.xml b/indra/newview/skins/default/xui/en/main_view.xml
index 71ca33a2d0..7c588fd10c 100644
--- a/indra/newview/skins/default/xui/en/main_view.xml
+++ b/indra/newview/skins/default/xui/en/main_view.xml
@@ -8,6 +8,12 @@
  tab_stop="false" 
  name="main_view"
  width="1024">
+  <panel top="0"
+     follows="all"
+     height="768"
+     mouse_opaque="false"
+     name="login_panel_holder"
+     width="1024"/>
   <layout_stack border_size="0"
                 follows="all"
                 mouse_opaque="false"
@@ -121,7 +127,7 @@
                       user_resize="false"
                       visible="false"
                       width="333"/>
-      </layout_stack>
+      </layout_stack>      
       <panel follows="all"
                     height="500"
                     left="0"
@@ -206,12 +212,6 @@
         name="hint_holder"
         mouse_opaque="false"
         follows="all"/>
-  <panel top="0"
-       follows="all"
-       height="768"
-       mouse_opaque="false"
-       name="login_panel_holder"
-       width="1024"/>
   <panel top="0"
          follows="all"
          height="768"
-- 
cgit v1.2.3


From 5cfb82892fec41d121b7c55a9fcea46d2d395897 Mon Sep 17 00:00:00 2001
From: callum <none@none>
Date: Thu, 30 Sep 2010 16:11:08 -0700
Subject: Code changes for "EXP-126 Create destination guide popup at bottom of
 screen"

---
 indra/newview/llviewermenu.cpp | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

(limited to 'indra/newview')

diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 07b6a9e642..0ff5181cc5 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -844,6 +844,25 @@ class LLAdvancedCheckFeature : public view_listener_t
 }
 };
 
+void LLDestinationGuideToggle()
+{
+	LLView* destination_guide = gViewerWindow->getRootView()->getChildView("destination_guide_container");
+	if ( destination_guide )
+	{
+		if ( destination_guide->getVisible() )
+		{
+			destination_guide->setVisible( FALSE );
+		}
+		else
+		{
+			destination_guide->setVisible( true );
+		}
+	}
+	else
+	{
+		llwarns << "ERROR: unable to find destination guide container" << llendl;
+	}
+};
 
 //////////////////
 // INFO DISPLAY //
@@ -8275,4 +8294,6 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLEditableSelectedMono(), "EditableSelectedMono");
 
 	view_listener_t::addMenu(new LLToggleUIHints(), "ToggleUIHints");
+
+	commit.add("DestinationGuide.toggle", boost::bind(&LLDestinationGuideToggle));
 }
-- 
cgit v1.2.3


From 7f003fa20df6ed60532271084696076ee61128de Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Thu, 30 Sep 2010 16:43:44 -0700
Subject: converted keys.ini to keys.xml and use LLInitParam parsing

---
 indra/newview/app_settings/keys.xml | 350 ++++++++++++++++++++++++++++++++++++
 indra/newview/llappviewer.cpp       |  20 ++-
 indra/newview/llviewerkeyboard.cpp  | 145 ++++++++++-----
 indra/newview/llviewerkeyboard.h    |  34 +++-
 4 files changed, 497 insertions(+), 52 deletions(-)
 create mode 100644 indra/newview/app_settings/keys.xml

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/keys.xml b/indra/newview/app_settings/keys.xml
new file mode 100644
index 0000000000..d085475c6c
--- /dev/null
+++ b/indra/newview/app_settings/keys.xml
@@ -0,0 +1,350 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<keys>
+  <first_person>
+    <binding key="A" mask="NONE" command="slide_left"/>
+    <binding key="D" mask="NONE" command="slide_right"/>
+    <binding key="W" mask="NONE" command="push_forward"/>
+    <binding key="S" mask="NONE" command="push_backward"/>
+    <binding key="E" mask="NONE" command="jump"/>
+    <binding key="C" mask="NONE" command="push_down"/>
+    <binding key="F" mask="NONE" command="toggle_fly"/>
+
+    <binding key="LEFT" mask="NONE" command="slide_left"/>
+    <binding key="RIGHT" mask="NONE" command="slide_right"/>
+    <binding key="UP" mask="NONE" command="push_forward"/>
+    <binding key="DOWN" mask="NONE" command="push_backward"/>
+    <binding key="PGUP" mask="NONE" command="jump"/>
+    <binding key="PGDN" mask="NONE" command="push_down"/>
+    <binding key="HOME" mask="NONE" command="toggle_fly"/>
+
+    <binding key="PAD_LEFT" mask="NONE" command="slide_left"/>
+    <binding key="PAD_RIGHT" mask="NONE" command="slide_right"/>
+    <binding key="PAD_UP" mask="NONE" command="push_forward"/>
+    <binding key="PAD_DOWN" mask="NONE" command="push_backward"/>
+    <binding key="PAD_PGUP" mask="NONE" command="jump"/>
+    <binding key="PAD_PGDN" mask="NONE" command="push_down"/>
+    <binding key="PAD_HOME" mask="NONE" command="toggle_fly"/>
+    <binding key="PAD_CENTER" mask="NONE" command="stop_moving"/>
+    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
+
+    <binding key="A" mask="SHIFT" command="slide_left"/>
+    <binding key="D" mask="SHIFT" command="slide_right"/>
+    <binding key="W" mask="SHIFT" command="push_forward"/>
+    <binding key="S" mask="SHIFT" command="push_backward"/>
+    <binding key="E" mask="SHIFT" command="jump"/>
+    <binding key="C" mask="SHIFT" command="push_down"/>
+    <binding key="F" mask="SHIFT" command="toggle_fly"/>
+
+    <binding key="SPACE" mask="NONE" command="stop_moving"/>
+    <binding key="ENTER" mask="NONE" command="start_chat"/>
+    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
+
+    <binding key="LEFT" mask="SHIFT" command="slide_left"/>
+    <binding key="RIGHT" mask="SHIFT" command="slide_right"/>
+    <binding key="UP" mask="SHIFT" command="push_forward"/>
+    <binding key="DOWN" mask="SHIFT" command="push_backward"/>
+    <binding key="PGUP" mask="SHIFT" command="jump"/>
+    <binding key="PGDN" mask="SHIFT" command="push_down"/>
+
+    <binding key="PAD_LEFT" mask="SHIFT" command="slide_left"/>
+    <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/>
+    <binding key="PAD_UP" mask="SHIFT" command="push_forward"/>
+    <binding key="PAD_DOWN" mask="SHIFT" command="push_backward"/>
+    <binding key="PAD_PGUP" mask="SHIFT" command="jump"/>
+    <binding key="PAD_PGDN" mask="SHIFT" command="push_down"/>
+    <binding key="PAD_HOME" mask="SHIFT" command="toggle_fly"/>
+    <binding key="PAD_ENTER" mask="SHIFT" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="SHIFT" command="start_gesture"/>
+  </first_person>
+  <third_person>
+    <binding key="A" mask="NONE" command="turn_left"/>
+    <binding key="D" mask="NONE" command="turn_right"/>
+    <binding key="A" mask="SHIFT" command="slide_left"/>
+    <binding key="D" mask="SHIFT" command="slide_right"/>
+    <binding key="W" mask="NONE" command="push_forward"/>
+    <binding key="S" mask="NONE" command="push_backward"/>
+    <binding key="W" mask="SHIFT" command="push_forward"/>
+    <binding key="S" mask="SHIFT" command="push_backward"/>
+    <binding key="E" mask="NONE" command="jump"/>
+    <binding key="C" mask="NONE" command="push_down"/>
+    <binding key="E" mask="SHIFT" command="jump"/>
+    <binding key="C" mask="SHIFT" command="push_down"/>
+
+    <binding key="F" mask="NONE" command="toggle_fly"/>
+    <binding key="F" mask="SHIFT" command="toggle_fly"/>
+
+    <binding key="SPACE" mask="NONE" command="stop_moving"/>
+    <binding key="ENTER" mask="NONE" command="start_chat"/>
+    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
+
+    <binding key="LEFT" mask="NONE" command="turn_left"/>
+    <binding key="LEFT" mask="SHIFT" command="slide_left"/>
+    <binding key="RIGHT" mask="NONE" command="turn_right"/>
+    <binding key="RIGHT" mask="SHIFT" command="slide_right"/>
+    <binding key="UP" mask="NONE" command="push_forward"/>
+    <binding key="DOWN" mask="NONE" command="push_backward"/>
+    <binding key="UP" mask="SHIFT" command="push_forward"/>
+    <binding key="DOWN" mask="SHIFT" command="push_backward"/>
+    <binding key="PGUP" mask="NONE" command="jump"/>
+    <binding key="PGDN" mask="NONE" command="push_down"/>
+    <binding key="PGUP" mask="SHIFT" command="jump"/>
+    <binding key="PGDN" mask="SHIFT" command="push_down"/>
+    <binding key="HOME" mask="SHIFT" command="toggle_fly"/>
+    <binding key="HOME" mask="NONE" command="toggle_fly"/>
+
+    <binding key="PAD_LEFT" mask="NONE" command="turn_left"/>
+    <binding key="PAD_LEFT" mask="SHIFT" command="slide_left"/>
+    <binding key="PAD_RIGHT" mask="NONE" command="turn_right"/>
+    <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/>
+    <binding key="PAD_UP" mask="NONE" command="push_forward"/>
+    <binding key="PAD_DOWN" mask="NONE" command="push_backward"/>
+    <binding key="PAD_UP" mask="SHIFT" command="push_forward"/>
+    <binding key="PAD_DOWN" mask="SHIFT" command="push_backward"/>
+    <binding key="PAD_PGUP" mask="NONE" command="jump"/>
+    <binding key="PAD_PGDN" mask="NONE" command="push_down"/>
+    <binding key="PAD_PGUP" mask="SHIFT" command="jump"/>
+    <binding key="PAD_PGDN" mask="SHIFT" command="push_down"/>
+    <binding key="PAD_HOME" mask="NONE" command="toggle_fly"/>
+    <binding key="PAD_HOME" mask="SHIFT" command="toggle_fly"/>
+    <binding key="PAD_CENTER" mask="NONE" command="stop_moving"/>
+    <binding key="PAD_CENTER" mask="SHIFT" command="stop_moving"/>
+    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
+    <binding key="PAD_ENTER" mask="SHIFT" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
+    <binding key="PAD_DIVIDE" mask="SHIFT" command="start_gesture"/>
+
+    <!--Camera controls in third person on Alt-->
+    <binding key="LEFT" mask="ALT" command="spin_around_cw"/>
+    <binding key="RIGHT" mask="ALT" command="spin_around_ccw"/>
+    <binding key="UP" mask="ALT" command="move_forward"/>
+    <binding key="DOWN" mask="ALT" command="move_backward"/>
+    <binding key="PGUP" mask="ALT" command="spin_over"/>
+    <binding key="PGDN" mask="ALT" command="spin_under"/>
+
+    <binding key="A" mask="ALT" command="spin_around_cw"/>
+    <binding key="D" mask="ALT" command="spin_around_ccw"/>
+    <binding key="W" mask="ALT" command="move_forward"/>
+    <binding key="S" mask="ALT" command="move_backward"/>
+    <binding key="E" mask="ALT" command="spin_over"/>
+    <binding key="C" mask="ALT" command="spin_under"/>
+
+    <binding key="PAD_LEFT" mask="ALT" command="spin_around_cw"/>
+    <binding key="PAD_RIGHT" mask="ALT" command="spin_around_ccw"/>
+    <binding key="PAD_UP" mask="ALT" command="move_forward"/>
+    <binding key="PAD_DOWN" mask="ALT" command="move_backward"/>
+    <binding key="PAD_PGUP" mask="ALT" command="spin_over"/>
+    <binding key="PAD_PGDN" mask="ALT" command="spin_under"/>
+    <binding key="PAD_ENTER" mask="ALT" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="ALT" command="start_gesture"/>
+
+    <!--mimic alt zoom behavior with keyboard only-->
+    <binding key="A" mask="CTL_ALT" command="spin_around_cw"/>
+    <binding key="D" mask="CTL_ALT" command="spin_around_ccw"/>
+    <binding key="W" mask="CTL_ALT" command="spin_over"/>
+    <binding key="S" mask="CTL_ALT" command="spin_under"/>
+    <binding key="E" mask="CTL_ALT" command="spin_over"/>
+    <binding key="C" mask="CTL_ALT" command="spin_under"/>
+
+    <binding key="LEFT" mask="CTL_ALT" command="spin_around_cw"/>
+    <binding key="RIGHT" mask="CTL_ALT" command="spin_around_ccw"/>
+    <binding key="UP" mask="CTL_ALT" command="spin_over"/>
+    <binding key="DOWN" mask="CTL_ALT" command="spin_under"/>
+    <binding key="PGUP" mask="CTL_ALT" command="spin_over"/>
+    <binding key="PGDN" mask="CTL_ALT" command="spin_under"/>
+
+    <binding key="PAD_LEFT" mask="CTL_ALT" command="spin_around_cw"/>
+    <binding key="PAD_RIGHT" mask="CTL_ALT" command="spin_around_ccw"/>
+    <binding key="PAD_UP" mask="CTL_ALT" command="spin_over"/>
+    <binding key="PAD_DOWN" mask="CTL_ALT" command="spin_under"/>
+    <binding key="PAD_PGUP" mask="CTL_ALT" command="spin_over"/>
+    <binding key="PAD_PGDN" mask="CTL_ALT" command="spin_under"/>
+    <binding key="PAD_ENTER" mask="CTL_ALT" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="CTL_ALT" command="start_gesture"/>
+
+    <!--Therefore pan on Alt-Shift-->
+    <binding key="A" mask="CTL_ALT_SHIFT" command="pan_left"/>
+    <binding key="D" mask="CTL_ALT_SHIFT" command="pan_right"/>
+    <binding key="W" mask="CTL_ALT_SHIFT" command="pan_up"/>
+    <binding key="S" mask="CTL_ALT_SHIFT" command="pan_down"/>
+
+    <binding key="LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
+    <binding key="RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
+    <binding key="UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
+    <binding key="DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
+
+    <binding key="PAD_LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
+    <binding key="PAD_RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
+    <binding key="PAD_UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
+    <binding key="PAD_DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
+    <binding key="PAD_ENTER" mask="CTL_ALT_SHIFT" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="CTL_ALT_SHIFT" command="start_gesture"/>
+  </third_person>
+
+  # Basic editing camera control
+  <edit>
+    <binding key="A" mask="NONE" command="spin_around_cw"/>
+    <binding key="D" mask="NONE" command="spin_around_ccw"/>
+    <binding key="W" mask="NONE" command="move_forward"/>
+    <binding key="S" mask="NONE" command="move_backward"/>
+    <binding key="E" mask="NONE" command="spin_over"/>
+    <binding key="C" mask="NONE" command="spin_under"/>
+    <binding key="ENTER" mask="NONE" command="start_chat"/>
+    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
+    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
+
+    <binding key="LEFT" mask="NONE" command="spin_around_cw"/>
+    <binding key="RIGHT" mask="NONE" command="spin_around_ccw"/>
+    <binding key="UP" mask="NONE" command="move_forward"/>
+    <binding key="DOWN" mask="NONE" command="move_backward"/>
+    <binding key="PGUP" mask="NONE" command="spin_over"/>
+    <binding key="PGDN" mask="NONE" command="spin_under"/>
+
+    <binding key="A" mask="SHIFT" command="pan_left"/>
+    <binding key="D" mask="SHIFT" command="pan_right"/>
+    <binding key="W" mask="SHIFT" command="pan_up"/>
+    <binding key="S" mask="SHIFT" command="pan_down"/>
+
+    <binding key="LEFT" mask="SHIFT" command="pan_left"/>
+    <binding key="RIGHT" mask="SHIFT" command="pan_right"/>
+    <binding key="UP" mask="SHIFT" command="pan_up"/>
+    <binding key="DOWN" mask="SHIFT" command="pan_down"/>
+
+    <!--Walking works with ALT held down.-->
+    <binding key="A" mask="ALT" command="slide_left"/>
+    <binding key="D" mask="ALT" command="slide_right"/>
+    <binding key="W" mask="ALT" command="push_forward"/>
+    <binding key="S" mask="ALT" command="push_backward"/>
+    <binding key="E" mask="ALT" command="jump"/>
+    <binding key="C" mask="ALT" command="push_down"/>
+
+    <binding key="LEFT" mask="ALT" command="slide_left"/>
+    <binding key="RIGHT" mask="ALT" command="slide_right"/>
+    <binding key="UP" mask="ALT" command="push_forward"/>
+    <binding key="DOWN" mask="ALT" command="push_backward"/>
+    <binding key="PGUP" mask="ALT" command="jump"/>
+    <binding key="PGDN" mask="ALT" command="push_down"/>
+    <binding key="HOME" mask="ALT" command="toggle_fly"/>
+
+    <binding key="PAD_LEFT" mask="ALT" command="slide_left"/>
+    <binding key="PAD_RIGHT" mask="ALT" command="slide_right"/>
+    <binding key="PAD_UP" mask="ALT" command="push_forward"/>
+    <binding key="PAD_DOWN" mask="ALT" command="push_backward"/>
+    <binding key="PAD_PGUP" mask="ALT" command="jump"/>
+    <binding key="PAD_PGDN" mask="ALT" command="push_down"/>
+    <binding key="PAD_ENTER" mask="ALT" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="ALT" command="start_gesture"/>
+  </edit>
+  <sitting>
+    <binding key="A" mask="ALT" command="spin_around_cw"/>
+    <binding key="D" mask="ALT" command="spin_around_ccw"/>
+    <binding key="W" mask="ALT" command="move_forward"/>
+    <binding key="S" mask="ALT" command="move_backward"/>
+    <binding key="E" mask="ALT" command="spin_over_sitting"/>
+    <binding key="C" mask="ALT" command="spin_under_sitting"/>
+
+    <binding key="LEFT" mask="ALT" command="spin_around_cw"/>
+    <binding key="RIGHT" mask="ALT" command="spin_around_ccw"/>
+    <binding key="UP" mask="ALT" command="move_forward"/>
+    <binding key="DOWN" mask="ALT" command="move_backward"/>
+    <binding key="PGUP" mask="ALT" command="spin_over"/>
+    <binding key="PGDN" mask="ALT" command="spin_under"/>
+
+    <binding key="A" mask="CTL_ALT" command="spin_around_cw"/>
+    <binding key="D" mask="CTL_ALT" command="spin_around_ccw"/>
+    <binding key="W" mask="CTL_ALT" command="spin_over"/>
+    <binding key="S" mask="CTL_ALT" command="spin_under"/>
+    <binding key="E" mask="CTL_ALT" command="spin_over"/>
+    <binding key="C" mask="CTL_ALT" command="spin_under"/>
+
+    <binding key="LEFT" mask="CTL_ALT" command="spin_around_cw"/>
+    <binding key="RIGHT" mask="CTL_ALT" command="spin_around_ccw"/>
+    <binding key="UP" mask="CTL_ALT" command="spin_over"/>
+    <binding key="DOWN" mask="CTL_ALT" command="spin_under"/>
+    <binding key="PGUP" mask="CTL_ALT" command="spin_over"/>
+    <binding key="PGDN" mask="CTL_ALT" command="spin_under"/>
+
+
+    <binding key="A" mask="NONE" command="spin_around_cw_sitting"/>
+    <binding key="D" mask="NONE" command="spin_around_ccw_sitting"/>
+    <binding key="W" mask="NONE" command="move_forward_sitting"/>
+    <binding key="S" mask="NONE" command="move_backward_sitting"/>
+    <binding key="E" mask="NONE" command="spin_over_sitting"/>
+    <binding key="C" mask="NONE" command="spin_under_sitting"/>
+
+    <binding key="LEFT" mask="NONE" command="spin_around_cw_sitting"/>
+    <binding key="RIGHT" mask="NONE" command="spin_around_ccw_sitting"/>
+    <binding key="UP" mask="NONE" command="move_forward_sitting"/>
+    <binding key="DOWN" mask="NONE" command="move_backward_sitting"/>
+    <binding key="PGUP" mask="NONE" command="spin_over_sitting"/>
+    <binding key="PGDN" mask="NONE" command="spin_under_sitting"/>
+
+    <binding key="PAD_LEFT" mask="NONE" command="spin_around_cw_sitting"/>
+    <binding key="PAD_RIGHT" mask="NONE" command="spin_around_ccw_sitting"/>
+    <binding key="PAD_UP" mask="NONE" command="move_forward_sitting"/>
+    <binding key="PAD_DOWN" mask="NONE" command="move_backward_sitting"/>
+    <binding key="PAD_PGUP" mask="NONE" command="spin_over_sitting"/>
+    <binding key="PAD_PGDN" mask="NONE" command="spin_under_sitting"/>
+    <binding key="PAD_CENTER" mask="NONE" command="stop_moving"/>
+    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
+
+    <!--these are for passing controls when sitting on vehicles-->
+    <binding key="A" mask="SHIFT" command="slide_left"/>
+    <binding key="D" mask="SHIFT" command="slide_right"/>
+    <binding key="LEFT" mask="SHIFT" command="slide_left"/>
+    <binding key="RIGHT" mask="SHIFT" command="slide_right"/>
+
+    <binding key="PAD_LEFT" mask="SHIFT" command="slide_left"/>
+    <binding key="PAD_RIGHT" mask="SHIFT" command="slide_right"/>
+    <binding key="PAD_ENTER" mask="SHIFT" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="SHIFT" command="start_gesture"/>
+
+    <!--pan on Alt-Shift-->
+    <binding key="A" mask="CTL_ALT_SHIFT" command="pan_left"/>
+    <binding key="D" mask="CTL_ALT_SHIFT" command="pan_right"/>
+    <binding key="W" mask="CTL_ALT_SHIFT" command="pan_up"/>
+    <binding key="S" mask="CTL_ALT_SHIFT" command="pan_down"/>
+
+    <binding key="LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
+    <binding key="RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
+    <binding key="UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
+    <binding key="DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
+
+    <binding key="PAD_LEFT" mask="CTL_ALT_SHIFT" command="pan_left"/>
+    <binding key="PAD_RIGHT" mask="CTL_ALT_SHIFT" command="pan_right"/>
+    <binding key="PAD_UP" mask="CTL_ALT_SHIFT" command="pan_up"/>
+    <binding key="PAD_DOWN" mask="CTL_ALT_SHIFT" command="pan_down"/>
+    <binding key="PAD_ENTER" mask="CTL_ALT_SHIFT" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="CTL_ALT_SHIFT" command="start_gesture"/>
+
+    <binding key="ENTER" mask="NONE" command="start_chat"/>
+    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
+  </sitting>
+  <edit_avatar>
+    <!--Avatar editing camera controls-->
+    <binding key="A" mask="NONE" command="edit_avatar_spin_cw"/>
+    <binding key="D" mask="NONE" command="edit_avatar_spin_ccw"/>
+    <binding key="W" mask="NONE" command="edit_avatar_move_forward"/>
+    <binding key="S" mask="NONE" command="edit_avatar_move_backward"/>
+    <binding key="E" mask="NONE" command="edit_avatar_spin_over"/>
+    <binding key="C" mask="NONE" command="edit_avatar_spin_under"/>
+    <binding key="LEFT" mask="NONE" command="edit_avatar_spin_cw"/>
+    <binding key="RIGHT" mask="NONE" command="edit_avatar_spin_ccw"/>
+    <binding key="UP" mask="NONE" command="edit_avatar_move_forward"/>
+    <binding key="DOWN" mask="NONE" command="edit_avatar_move_backward"/>
+    <binding key="PGUP" mask="NONE" command="edit_avatar_spin_over"/>
+    <binding key="PGDN" mask="NONE" command="edit_avatar_spin_under"/>
+    <binding key="ENTER" mask="NONE" command="start_chat"/>
+    <binding key="DIVIDE" mask="NONE" command="start_gesture"/>
+    <binding key="PAD_LEFT" mask="NONE" command="edit_avatar_spin_cw"/>
+    <binding key="PAD_RIGHT" mask="NONE" command="edit_avatar_spin_ccw"/>
+    <binding key="PAD_UP" mask="NONE" command="edit_avatar_move_forward"/>
+    <binding key="PAD_DOWN" mask="NONE" command="edit_avatar_move_backward"/>
+    <binding key="PAD_PGUP" mask="NONE" command="edit_avatar_spin_over"/>
+    <binding key="PAD_PGDN" mask="NONE" command="edit_avatar_spin_under"/>
+    <binding key="PAD_ENTER" mask="NONE" command="start_chat"/>
+    <binding key="PAD_DIVIDE" mask="NONE" command="start_gesture"/>
+  </edit_avatar>
+</keys>
\ No newline at end of file
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 956f67df86..a9bdabe794 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -820,16 +820,22 @@ bool LLAppViewer::init()
 	gGLManager.getGLInfo(gDebugInfo);
 	gGLManager.printGLInfoString();
 
-	//load key settings
-	bind_keyboard_functions();
-
 	// Load Default bindings
-	if (!gViewerKeyboard.loadBindings(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"keys.ini")))
+	std::string key_bindings_file = gDirUtilp->findFile("keys.xml",
+														gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
+														gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
+
+
+	if (!gViewerKeyboard.loadBindingsXML(key_bindings_file))
 	{
-		LL_ERRS("InitInfo") << "Unable to open keys.ini" << LL_ENDL;
+		std::string key_bindings_file = gDirUtilp->findFile("keys.ini",
+															gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
+															gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
+		if (!gViewerKeyboard.loadBindings(key_bindings_file))
+		{
+			LL_ERRS("InitInfo") << "Unable to open keys.ini" << LL_ENDL;
+		}
 	}
-	// Load Custom bindings (override defaults)
-	gViewerKeyboard.loadBindings(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"custom_keys.ini"));
 
 	// If we don't have the right GL requirements, exit.
 	if (!gGLManager.mHasRequirements && !gNoRender)
diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp
index d7e15e7d6c..570f372950 100644
--- a/indra/newview/llviewerkeyboard.cpp
+++ b/indra/newview/llviewerkeyboard.cpp
@@ -40,6 +40,7 @@
 #include "llviewerwindow.h"
 #include "llvoavatarself.h"
 #include "llfloatercamera.h"
+#include "llinitparam.h"
 
 //
 // Constants
@@ -53,6 +54,11 @@ const S32 NUDGE_FRAMES = 2;
 const F32 ORBIT_NUDGE_RATE = 0.05f;  // fraction of normal speed
 const F32 YAW_NUDGE_RATE = 0.05f;  // fraction of normal speed
 
+struct LLKeyboardActionRegistry 
+:	public LLRegistrySingleton<std::string, boost::function<void (EKeystate keystate)>, LLKeyboardActionRegistry>
+{
+};
+
 LLViewerKeyboard gViewerKeyboard;
 
 void agent_jump( EKeystate s )
@@ -550,49 +556,47 @@ void start_gesture( EKeystate s )
 	}
 }
 
-void bind_keyboard_functions()
-{
-	gViewerKeyboard.bindNamedFunction("jump", agent_jump);
-	gViewerKeyboard.bindNamedFunction("push_down", agent_push_down);
-	gViewerKeyboard.bindNamedFunction("push_forward", agent_push_forward);
-	gViewerKeyboard.bindNamedFunction("push_backward", agent_push_backward);
-	gViewerKeyboard.bindNamedFunction("look_up", agent_look_up);
-	gViewerKeyboard.bindNamedFunction("look_down", agent_look_down);
-	gViewerKeyboard.bindNamedFunction("toggle_fly", agent_toggle_fly);
-	gViewerKeyboard.bindNamedFunction("turn_left", agent_turn_left);
-	gViewerKeyboard.bindNamedFunction("turn_right", agent_turn_right);
-	gViewerKeyboard.bindNamedFunction("slide_left", agent_slide_left);
-	gViewerKeyboard.bindNamedFunction("slide_right", agent_slide_right);
-	gViewerKeyboard.bindNamedFunction("spin_around_ccw", camera_spin_around_ccw);
-	gViewerKeyboard.bindNamedFunction("spin_around_cw", camera_spin_around_cw);
-	gViewerKeyboard.bindNamedFunction("spin_around_ccw_sitting", camera_spin_around_ccw_sitting);
-	gViewerKeyboard.bindNamedFunction("spin_around_cw_sitting", camera_spin_around_cw_sitting);
-	gViewerKeyboard.bindNamedFunction("spin_over", camera_spin_over);
-	gViewerKeyboard.bindNamedFunction("spin_under", camera_spin_under);
-	gViewerKeyboard.bindNamedFunction("spin_over_sitting", camera_spin_over_sitting);
-	gViewerKeyboard.bindNamedFunction("spin_under_sitting", camera_spin_under_sitting);
-	gViewerKeyboard.bindNamedFunction("move_forward", camera_move_forward);
-	gViewerKeyboard.bindNamedFunction("move_backward", camera_move_backward);
-	gViewerKeyboard.bindNamedFunction("move_forward_sitting", camera_move_forward_sitting);
-	gViewerKeyboard.bindNamedFunction("move_backward_sitting", camera_move_backward_sitting);
-	gViewerKeyboard.bindNamedFunction("pan_up", camera_pan_up);
-	gViewerKeyboard.bindNamedFunction("pan_down", camera_pan_down);
-	gViewerKeyboard.bindNamedFunction("pan_left", camera_pan_left);
-	gViewerKeyboard.bindNamedFunction("pan_right", camera_pan_right);
-	gViewerKeyboard.bindNamedFunction("pan_in", camera_pan_in);
-	gViewerKeyboard.bindNamedFunction("pan_out", camera_pan_out);
-	gViewerKeyboard.bindNamedFunction("move_forward_fast", camera_move_forward_fast);
-	gViewerKeyboard.bindNamedFunction("move_backward_fast", camera_move_backward_fast);
-	gViewerKeyboard.bindNamedFunction("edit_avatar_spin_ccw", edit_avatar_spin_ccw);
-	gViewerKeyboard.bindNamedFunction("edit_avatar_spin_cw", edit_avatar_spin_cw);
-	gViewerKeyboard.bindNamedFunction("edit_avatar_spin_over", edit_avatar_spin_over);
-	gViewerKeyboard.bindNamedFunction("edit_avatar_spin_under", edit_avatar_spin_under);
-	gViewerKeyboard.bindNamedFunction("edit_avatar_move_forward", edit_avatar_move_forward);
-	gViewerKeyboard.bindNamedFunction("edit_avatar_move_backward", edit_avatar_move_backward);
-	gViewerKeyboard.bindNamedFunction("stop_moving", stop_moving);
-	gViewerKeyboard.bindNamedFunction("start_chat", start_chat);
-	gViewerKeyboard.bindNamedFunction("start_gesture", start_gesture);
-}
+#define REGISTER_KEYBOARD_ACTION(KEY, ACTION) LLREGISTER_STATIC(LLKeyboardActionRegistry, KEY, ACTION);
+REGISTER_KEYBOARD_ACTION("jump", agent_jump);
+REGISTER_KEYBOARD_ACTION("push_down", agent_push_down);
+REGISTER_KEYBOARD_ACTION("push_forward", agent_push_forward);
+REGISTER_KEYBOARD_ACTION("push_backward", agent_push_backward);
+REGISTER_KEYBOARD_ACTION("look_up", agent_look_up);
+REGISTER_KEYBOARD_ACTION("look_down", agent_look_down);
+REGISTER_KEYBOARD_ACTION("toggle_fly", agent_toggle_fly);
+REGISTER_KEYBOARD_ACTION("turn_left", agent_turn_left);
+REGISTER_KEYBOARD_ACTION("turn_right", agent_turn_right);
+REGISTER_KEYBOARD_ACTION("slide_left", agent_slide_left);
+REGISTER_KEYBOARD_ACTION("slide_right", agent_slide_right);
+REGISTER_KEYBOARD_ACTION("spin_around_ccw", camera_spin_around_ccw);
+REGISTER_KEYBOARD_ACTION("spin_around_cw", camera_spin_around_cw);
+REGISTER_KEYBOARD_ACTION("spin_around_ccw_sitting", camera_spin_around_ccw_sitting);
+REGISTER_KEYBOARD_ACTION("spin_around_cw_sitting", camera_spin_around_cw_sitting);
+REGISTER_KEYBOARD_ACTION("spin_over", camera_spin_over);
+REGISTER_KEYBOARD_ACTION("spin_under", camera_spin_under);
+REGISTER_KEYBOARD_ACTION("spin_over_sitting", camera_spin_over_sitting);
+REGISTER_KEYBOARD_ACTION("spin_under_sitting", camera_spin_under_sitting);
+REGISTER_KEYBOARD_ACTION("move_forward", camera_move_forward);
+REGISTER_KEYBOARD_ACTION("move_backward", camera_move_backward);
+REGISTER_KEYBOARD_ACTION("move_forward_sitting", camera_move_forward_sitting);
+REGISTER_KEYBOARD_ACTION("move_backward_sitting", camera_move_backward_sitting);
+REGISTER_KEYBOARD_ACTION("pan_up", camera_pan_up);
+REGISTER_KEYBOARD_ACTION("pan_down", camera_pan_down);
+REGISTER_KEYBOARD_ACTION("pan_left", camera_pan_left);
+REGISTER_KEYBOARD_ACTION("pan_right", camera_pan_right);
+REGISTER_KEYBOARD_ACTION("pan_in", camera_pan_in);
+REGISTER_KEYBOARD_ACTION("pan_out", camera_pan_out);
+REGISTER_KEYBOARD_ACTION("move_forward_fast", camera_move_forward_fast);
+REGISTER_KEYBOARD_ACTION("move_backward_fast", camera_move_backward_fast);
+REGISTER_KEYBOARD_ACTION("edit_avatar_spin_ccw", edit_avatar_spin_ccw);
+REGISTER_KEYBOARD_ACTION("edit_avatar_spin_cw", edit_avatar_spin_cw);
+REGISTER_KEYBOARD_ACTION("edit_avatar_spin_over", edit_avatar_spin_over);
+REGISTER_KEYBOARD_ACTION("edit_avatar_spin_under", edit_avatar_spin_under);
+REGISTER_KEYBOARD_ACTION("edit_avatar_move_forward", edit_avatar_move_forward);
+REGISTER_KEYBOARD_ACTION("edit_avatar_move_backward", edit_avatar_move_backward);
+REGISTER_KEYBOARD_ACTION("stop_moving", stop_moving);
+REGISTER_KEYBOARD_ACTION("start_chat", start_chat);
+REGISTER_KEYBOARD_ACTION("start_gesture", start_gesture);
 
 LLViewerKeyboard::LLViewerKeyboard() :
 	mNamedFunctionCount(0)
@@ -764,6 +768,61 @@ BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, c
 	return TRUE;
 }
 
+LLViewerKeyboard::KeyBinding::KeyBinding()
+:	key("key"),
+	mask("mask"),
+	command("command")
+{}
+
+LLViewerKeyboard::KeyMode::KeyMode(EKeyboardMode _mode)
+:	bindings("binding"),
+	mode(_mode)
+{}
+
+LLViewerKeyboard::Keys::Keys()
+:	first_person("first_person", KeyMode(MODE_FIRST_PERSON)),
+	third_person("third_person", KeyMode(MODE_THIRD_PERSON)),
+	edit("edit", KeyMode(MODE_EDIT)),
+	sitting("sitting", KeyMode(MODE_SITTING)),
+	edit_avatar("edit_avatar", KeyMode(MODE_EDIT_AVATAR))
+{}
+
+S32 LLViewerKeyboard::loadBindingsXML(const std::string& filename)
+{
+	S32 binding_count = 0;
+	Keys keys;
+	LLSimpleXUIParser parser;
+
+	if (parser.readXUI(filename, keys) 
+		&& keys.validateBlock())
+	{
+		binding_count += loadBindingMode(keys.first_person);
+		binding_count += loadBindingMode(keys.third_person);
+		binding_count += loadBindingMode(keys.edit);
+		binding_count += loadBindingMode(keys.sitting);
+		binding_count += loadBindingMode(keys.edit_avatar);
+	}
+	return binding_count;
+}
+
+S32 LLViewerKeyboard::loadBindingMode(const LLViewerKeyboard::KeyMode& keymode)
+{
+	S32 binding_count = 0;
+	for (LLInitParam::ParamIterator<KeyBinding>::const_iterator it = keymode.bindings.begin(), 
+			end_it = keymode.bindings.end();
+		it != end_it;
+		++it)
+	{
+		KEY key;
+		MASK mask;
+		LLKeyboard::keyFromString(it->key, &key);
+		LLKeyboard::maskFromString(it->mask, &mask);
+		bindKey(keymode.mode, key, mask, it->command);
+		binding_count++;
+	}
+
+	return binding_count;
+}
 
 S32 LLViewerKeyboard::loadBindings(const std::string& filename)
 {
diff --git a/indra/newview/llviewerkeyboard.h b/indra/newview/llviewerkeyboard.h
index 2fa5d5dfa6..6e758cc7b3 100644
--- a/indra/newview/llviewerkeyboard.h
+++ b/indra/newview/llviewerkeyboard.h
@@ -55,10 +55,36 @@ typedef enum e_keyboard_mode
 
 void bind_keyboard_functions();
 
-
 class LLViewerKeyboard
 {
 public:
+	struct KeyBinding : public LLInitParam::Block<KeyBinding>
+	{
+		Mandatory<std::string>	key,
+								mask,
+								command;
+
+		KeyBinding();
+	};
+
+	struct KeyMode : public LLInitParam::Block<KeyMode>
+	{
+		Multiple<KeyBinding>		bindings;
+		EKeyboardMode				mode;
+		KeyMode(EKeyboardMode mode);
+	};
+
+	struct Keys : public LLInitParam::Block<Keys>
+	{
+		Optional<KeyMode>	first_person,
+							third_person,
+							edit,
+							sitting,
+							edit_avatar;
+
+		Keys();
+	};
+
 	LLViewerKeyboard();
 
 	BOOL			handleKey(KEY key, MASK mask, BOOL repeated);
@@ -66,13 +92,17 @@ public:
 	void			bindNamedFunction(const std::string& name, LLKeyFunc func);
 
 	S32				loadBindings(const std::string& filename);										// returns number bound, 0 on error
+	S32				loadBindingsXML(const std::string& filename);										// returns number bound, 0 on error
 	EKeyboardMode	getMode();
 
 	BOOL			modeFromString(const std::string& string, S32 *mode);			// False on failure
 
 	void			scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level);
-protected:
+
+private:
+	S32				loadBindingMode(const LLViewerKeyboard::KeyMode& keymode);
 	BOOL			bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name);
+
 	S32				mNamedFunctionCount;
 	LLNamedFunction	mNamedFunctions[MAX_NAMED_FUNCTIONS];
 
-- 
cgit v1.2.3


From a5e0c51de9acdbffa385c1fc6c8d6e7a18c9908a Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Thu, 30 Sep 2010 20:07:50 -0700
Subject: custom skylight key bindings

---
 indra/newview/app_settings/keys.ini | 357 ------------------------------------
 indra/newview/llviewerkeyboard.cpp  |  35 ++--
 indra/newview/llviewerkeyboard.h    |   5 -
 3 files changed, 11 insertions(+), 386 deletions(-)
 delete mode 100644 indra/newview/app_settings/keys.ini

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/keys.ini b/indra/newview/app_settings/keys.ini
deleted file mode 100644
index b79e5bf508..0000000000
--- a/indra/newview/app_settings/keys.ini
+++ /dev/null
@@ -1,357 +0,0 @@
-# keys.ini
-#
-# keyboard binding initialization
-#
-# comments must have # in the first column
-# blank lines OK
-#
-# Format:
-# mode key mask function
-#
-# mode must be one of FIRST_PERSON, THIRD_PERSON, EDIT, EDIT_AVATAR, or CONVERSATION
-# key must be upper case, or SPACE, HOME, END, PGUP, PGDN, LEFT, RIGHT, UP, DOWN,
-#     or one of ,.;'[]
-# mask must be NONE, SHIFT, ALT, ALT_SHIFT.
-# Control is reserved for user commands.
-# function must be a function named in llkeyboard.cpp
-
-FIRST_PERSON	A		NONE		slide_left
-FIRST_PERSON	D		NONE		slide_right
-FIRST_PERSON	W		NONE		push_forward
-FIRST_PERSON	S		NONE		push_backward
-FIRST_PERSON	E		NONE		jump
-FIRST_PERSON	C		NONE		push_down
-FIRST_PERSON	F		NONE		toggle_fly
-
-FIRST_PERSON	LEFT	NONE		slide_left
-FIRST_PERSON	RIGHT	NONE		slide_right
-FIRST_PERSON	UP		NONE		push_forward
-FIRST_PERSON	DOWN	NONE		push_backward
-FIRST_PERSON	PGUP	NONE		jump
-FIRST_PERSON	PGDN	NONE		push_down
-FIRST_PERSON	HOME	NONE		toggle_fly
-
-FIRST_PERSON	PAD_LEFT	NONE		slide_left
-FIRST_PERSON	PAD_RIGHT	NONE		slide_right
-FIRST_PERSON	PAD_UP		NONE		push_forward
-FIRST_PERSON	PAD_DOWN	NONE		push_backward
-FIRST_PERSON	PAD_PGUP	NONE		jump
-FIRST_PERSON	PAD_PGDN	NONE		push_down
-FIRST_PERSON	PAD_HOME	NONE		toggle_fly
-FIRST_PERSON	PAD_CENTER	NONE		stop_moving
-FIRST_PERSON	PAD_ENTER	NONE		start_chat
-FIRST_PERSON	PAD_DIVIDE	NONE		start_gesture
-
-FIRST_PERSON	A		SHIFT		slide_left
-FIRST_PERSON	D		SHIFT		slide_right
-FIRST_PERSON	W		SHIFT		push_forward
-FIRST_PERSON	S		SHIFT		push_backward
-FIRST_PERSON	E		SHIFT		jump
-FIRST_PERSON	C		SHIFT		push_down
-FIRST_PERSON	F		SHIFT		toggle_fly
-
-FIRST_PERSON	SPACE	NONE		stop_moving
-FIRST_PERSON	ENTER	NONE		start_chat
-FIRST_PERSON	DIVIDE	NONE		start_gesture
-
-FIRST_PERSON	LEFT	SHIFT		slide_left
-FIRST_PERSON	RIGHT	SHIFT		slide_right
-FIRST_PERSON	UP		SHIFT		push_forward
-FIRST_PERSON	DOWN	SHIFT		push_backward
-FIRST_PERSON	PGUP	SHIFT		jump
-FIRST_PERSON	PGDN	SHIFT		push_down
-
-FIRST_PERSON	PAD_LEFT	SHIFT		slide_left
-FIRST_PERSON	PAD_RIGHT	SHIFT		slide_right
-FIRST_PERSON	PAD_UP		SHIFT		push_forward
-FIRST_PERSON	PAD_DOWN	SHIFT		push_backward
-FIRST_PERSON	PAD_PGUP	SHIFT		jump
-FIRST_PERSON	PAD_PGDN	SHIFT		push_down
-FIRST_PERSON	PAD_HOME	SHIFT		toggle_fly
-FIRST_PERSON	PAD_ENTER	SHIFT		start_chat
-FIRST_PERSON	PAD_DIVIDE	SHIFT		start_gesture
-
-THIRD_PERSON	A		NONE		turn_left
-THIRD_PERSON	D		NONE		turn_right
-THIRD_PERSON	A		SHIFT		slide_left
-THIRD_PERSON	D		SHIFT		slide_right
-THIRD_PERSON	W		NONE		push_forward
-THIRD_PERSON	S		NONE		push_backward
-THIRD_PERSON	W		SHIFT		push_forward
-THIRD_PERSON	S		SHIFT		push_backward
-THIRD_PERSON	E		NONE		jump
-THIRD_PERSON	C		NONE		push_down
-THIRD_PERSON	E		SHIFT		jump
-THIRD_PERSON	C		SHIFT		push_down
-
-THIRD_PERSON	F		NONE		toggle_fly
-THIRD_PERSON	F		SHIFT		toggle_fly
-
-THIRD_PERSON	SPACE	NONE		stop_moving
-THIRD_PERSON	ENTER	NONE		start_chat
-THIRD_PERSON	DIVIDE	NONE		start_gesture
-
-THIRD_PERSON	LEFT	NONE		turn_left
-THIRD_PERSON	LEFT	SHIFT		slide_left
-THIRD_PERSON	RIGHT	NONE		turn_right
-THIRD_PERSON	RIGHT	SHIFT		slide_right
-THIRD_PERSON	UP		NONE		push_forward
-THIRD_PERSON	DOWN	NONE		push_backward
-THIRD_PERSON	UP		SHIFT		push_forward
-THIRD_PERSON	DOWN	SHIFT		push_backward
-THIRD_PERSON	PGUP	NONE		jump
-THIRD_PERSON	PGDN	NONE		push_down
-THIRD_PERSON	PGUP	SHIFT		jump
-THIRD_PERSON	PGDN	SHIFT		push_down
-THIRD_PERSON	HOME	SHIFT		toggle_fly
-THIRD_PERSON	HOME	NONE		toggle_fly
-
-THIRD_PERSON	PAD_LEFT	NONE		turn_left
-THIRD_PERSON	PAD_LEFT	SHIFT		slide_left
-THIRD_PERSON	PAD_RIGHT	NONE		turn_right
-THIRD_PERSON	PAD_RIGHT	SHIFT		slide_right
-THIRD_PERSON	PAD_UP		NONE		push_forward
-THIRD_PERSON	PAD_DOWN	NONE		push_backward
-THIRD_PERSON	PAD_UP		SHIFT		push_forward
-THIRD_PERSON	PAD_DOWN	SHIFT		push_backward
-THIRD_PERSON	PAD_PGUP	NONE		jump
-THIRD_PERSON	PAD_PGDN	NONE		push_down
-THIRD_PERSON	PAD_PGUP	SHIFT		jump
-THIRD_PERSON	PAD_PGDN	SHIFT		push_down
-THIRD_PERSON	PAD_HOME	NONE		toggle_fly
-THIRD_PERSON	PAD_HOME	SHIFT		toggle_fly
-THIRD_PERSON	PAD_CENTER	NONE		stop_moving
-THIRD_PERSON	PAD_CENTER	SHIFT		stop_moving
-THIRD_PERSON	PAD_ENTER	NONE		start_chat
-THIRD_PERSON	PAD_ENTER	SHIFT		start_chat
-THIRD_PERSON	PAD_DIVIDE	NONE		start_gesture
-THIRD_PERSON	PAD_DIVIDE	SHIFT		start_gesture
-
-# Camera controls in third person on Alt
-THIRD_PERSON	LEFT	ALT			spin_around_cw
-THIRD_PERSON	RIGHT	ALT			spin_around_ccw
-THIRD_PERSON	UP		ALT			move_forward
-THIRD_PERSON	DOWN	ALT			move_backward
-THIRD_PERSON	PGUP	ALT			spin_over
-THIRD_PERSON	PGDN	ALT			spin_under
-
-THIRD_PERSON	A		ALT			spin_around_cw
-THIRD_PERSON	D		ALT			spin_around_ccw
-THIRD_PERSON	W		ALT			move_forward
-THIRD_PERSON	S		ALT			move_backward
-THIRD_PERSON	E		ALT			spin_over
-THIRD_PERSON	C		ALT			spin_under
-
-THIRD_PERSON	PAD_LEFT	ALT			spin_around_cw
-THIRD_PERSON	PAD_RIGHT	ALT			spin_around_ccw
-THIRD_PERSON	PAD_UP		ALT			move_forward
-THIRD_PERSON	PAD_DOWN	ALT			move_backward
-THIRD_PERSON	PAD_PGUP	ALT			spin_over
-THIRD_PERSON	PAD_PGDN	ALT			spin_under
-THIRD_PERSON	PAD_ENTER	ALT			start_chat
-THIRD_PERSON	PAD_DIVIDE	ALT			start_gesture
-
-# mimic alt zoom behavior with keyboard only
-THIRD_PERSON	A		CTL_ALT			spin_around_cw
-THIRD_PERSON	D		CTL_ALT			spin_around_ccw
-THIRD_PERSON	W		CTL_ALT			spin_over
-THIRD_PERSON	S		CTL_ALT			spin_under
-THIRD_PERSON	E		CTL_ALT			spin_over
-THIRD_PERSON	C		CTL_ALT			spin_under
-
-THIRD_PERSON	LEFT	CTL_ALT			spin_around_cw
-THIRD_PERSON	RIGHT	CTL_ALT			spin_around_ccw
-THIRD_PERSON	UP		CTL_ALT			spin_over
-THIRD_PERSON	DOWN	CTL_ALT			spin_under
-THIRD_PERSON	PGUP	CTL_ALT			spin_over
-THIRD_PERSON	PGDN	CTL_ALT			spin_under
-
-THIRD_PERSON	PAD_LEFT	CTL_ALT			spin_around_cw
-THIRD_PERSON	PAD_RIGHT	CTL_ALT			spin_around_ccw
-THIRD_PERSON	PAD_UP		CTL_ALT			spin_over
-THIRD_PERSON	PAD_DOWN	CTL_ALT			spin_under
-THIRD_PERSON	PAD_PGUP	CTL_ALT			spin_over
-THIRD_PERSON	PAD_PGDN	CTL_ALT			spin_under
-THIRD_PERSON	PAD_ENTER	CTL_ALT			start_chat
-THIRD_PERSON	PAD_DIVIDE	CTL_ALT			start_gesture
-
-# Therefore pan on Alt-Shift
-THIRD_PERSON	A		CTL_ALT_SHIFT	pan_left
-THIRD_PERSON	D		CTL_ALT_SHIFT	pan_right
-THIRD_PERSON	W		CTL_ALT_SHIFT	pan_up
-THIRD_PERSON	S		CTL_ALT_SHIFT	pan_down
-
-THIRD_PERSON	LEFT	CTL_ALT_SHIFT	pan_left
-THIRD_PERSON	RIGHT	CTL_ALT_SHIFT	pan_right
-THIRD_PERSON	UP		CTL_ALT_SHIFT	pan_up
-THIRD_PERSON	DOWN	CTL_ALT_SHIFT	pan_down
-
-THIRD_PERSON	PAD_LEFT	CTL_ALT_SHIFT	pan_left
-THIRD_PERSON	PAD_RIGHT	CTL_ALT_SHIFT	pan_right
-THIRD_PERSON	PAD_UP		CTL_ALT_SHIFT	pan_up
-THIRD_PERSON	PAD_DOWN	CTL_ALT_SHIFT	pan_down
-THIRD_PERSON	PAD_ENTER	CTL_ALT_SHIFT	start_chat
-THIRD_PERSON	PAD_DIVIDE	CTL_ALT_SHIFT	start_gesture
-
-# Basic editing camera control
-EDIT			A		NONE		spin_around_cw
-EDIT			D		NONE		spin_around_ccw
-EDIT			W		NONE		move_forward
-EDIT			S		NONE		move_backward
-EDIT			E		NONE		spin_over
-EDIT			C		NONE		spin_under
-EDIT			ENTER	NONE		start_chat
-EDIT			DIVIDE	NONE		start_gesture
-EDIT			PAD_ENTER	NONE	start_chat
-EDIT			PAD_DIVIDE	NONE	start_gesture
-
-EDIT			LEFT	NONE		spin_around_cw
-EDIT			RIGHT	NONE		spin_around_ccw
-EDIT			UP		NONE		move_forward
-EDIT			DOWN	NONE		move_backward
-EDIT			PGUP	NONE		spin_over
-EDIT			PGDN	NONE		spin_under
-
-EDIT			A		SHIFT		pan_left
-EDIT			D		SHIFT		pan_right
-EDIT			W		SHIFT		pan_up
-EDIT			S		SHIFT		pan_down
-
-EDIT			LEFT	SHIFT		pan_left
-EDIT			RIGHT	SHIFT		pan_right
-EDIT			UP		SHIFT		pan_up
-EDIT			DOWN	SHIFT		pan_down
-
-# Walking works with ALT held down.
-EDIT			A		ALT			slide_left
-EDIT			D		ALT			slide_right
-EDIT			W		ALT			push_forward
-EDIT			S		ALT			push_backward
-EDIT			E		ALT			jump
-EDIT			C		ALT			push_down
-
-EDIT			LEFT	ALT			slide_left
-EDIT			RIGHT	ALT			slide_right
-EDIT			UP		ALT			push_forward
-EDIT			DOWN	ALT			push_backward
-EDIT			PGUP	ALT			jump
-EDIT			PGDN	ALT			push_down
-EDIT			HOME	ALT			toggle_fly
-
-EDIT			PAD_LEFT	ALT			slide_left
-EDIT			PAD_RIGHT	ALT			slide_right
-EDIT			PAD_UP		ALT			push_forward
-EDIT			PAD_DOWN	ALT			push_backward
-EDIT			PAD_PGUP	ALT			jump
-EDIT			PAD_PGDN	ALT			push_down
-EDIT			PAD_ENTER	ALT			start_chat
-EDIT			PAD_DIVIDE	ALT			start_gesture
-
-SITTING			A	ALT			spin_around_cw
-SITTING			D	ALT			spin_around_ccw
-SITTING			W	ALT			move_forward
-SITTING			S	ALT			move_backward
-SITTING			E	ALT			spin_over_sitting
-SITTING			C	ALT			spin_under_sitting
-
-SITTING			LEFT	ALT			spin_around_cw
-SITTING			RIGHT	ALT			spin_around_ccw
-SITTING			UP		ALT			move_forward
-SITTING			DOWN	ALT			move_backward
-SITTING			PGUP	ALT			spin_over
-SITTING			PGDN	ALT			spin_under
-
-SITTING			A	CTL_ALT			spin_around_cw
-SITTING 		D	CTL_ALT			spin_around_ccw
-SITTING			W	CTL_ALT			spin_over
-SITTING			S	CTL_ALT			spin_under
-SITTING 		E	CTL_ALT			spin_over
-SITTING			C	CTL_ALT			spin_under
-
-SITTING			LEFT	CTL_ALT			spin_around_cw
-SITTING			RIGHT	CTL_ALT			spin_around_ccw
-SITTING			UP		CTL_ALT			spin_over
-SITTING			DOWN	CTL_ALT			spin_under
-SITTING			PGUP	CTL_ALT			spin_over
-SITTING			PGDN	CTL_ALT			spin_under
-
-
-SITTING			A		NONE		spin_around_cw_sitting
-SITTING			D		NONE		spin_around_ccw_sitting
-SITTING			W		NONE		move_forward_sitting
-SITTING			S		NONE		move_backward_sitting
-SITTING			E		NONE		spin_over_sitting
-SITTING			C		NONE		spin_under_sitting
-
-SITTING			LEFT	NONE		spin_around_cw_sitting
-SITTING			RIGHT	NONE		spin_around_ccw_sitting
-SITTING			UP		NONE		move_forward_sitting
-SITTING			DOWN	NONE		move_backward_sitting
-SITTING			PGUP	NONE		spin_over_sitting
-SITTING			PGDN	NONE		spin_under_sitting
-
-SITTING			PAD_LEFT	NONE		spin_around_cw_sitting
-SITTING			PAD_RIGHT	NONE		spin_around_ccw_sitting
-SITTING			PAD_UP		NONE		move_forward_sitting
-SITTING			PAD_DOWN	NONE		move_backward_sitting
-SITTING			PAD_PGUP	NONE		spin_over_sitting
-SITTING			PAD_PGDN	NONE		spin_under_sitting
-SITTING			PAD_CENTER	NONE		stop_moving
-SITTING			PAD_ENTER	NONE		start_chat
-SITTING			PAD_DIVIDE	NONE		start_gesture
-
-# these are for passing controls when sitting on vehicles
-SITTING			A		SHIFT		slide_left
-SITTING			D		SHIFT		slide_right
-SITTING			LEFT	SHIFT		slide_left
-SITTING			RIGHT	SHIFT		slide_right
-
-SITTING			PAD_LEFT	SHIFT		slide_left
-SITTING			PAD_RIGHT	SHIFT		slide_right
-SITTING			PAD_ENTER	SHIFT		start_chat
-SITTING			PAD_DIVIDE	SHIFT		start_gesture
-
-# pan on Alt-Shift
-SITTING			A		CTL_ALT_SHIFT	pan_left
-SITTING			D		CTL_ALT_SHIFT	pan_right
-SITTING			W		CTL_ALT_SHIFT	pan_up
-SITTING			S		CTL_ALT_SHIFT	pan_down
-
-SITTING			LEFT	CTL_ALT_SHIFT	pan_left
-SITTING			RIGHT	CTL_ALT_SHIFT	pan_right
-SITTING			UP		CTL_ALT_SHIFT	pan_up
-SITTING			DOWN	CTL_ALT_SHIFT	pan_down
-
-SITTING			PAD_LEFT	CTL_ALT_SHIFT	pan_left
-SITTING			PAD_RIGHT	CTL_ALT_SHIFT	pan_right
-SITTING			PAD_UP		CTL_ALT_SHIFT	pan_up
-SITTING			PAD_DOWN	CTL_ALT_SHIFT	pan_down
-SITTING			PAD_ENTER	CTL_ALT_SHIFT	start_chat
-SITTING			PAD_DIVIDE	CTL_ALT_SHIFT	start_gesture
-
-SITTING			ENTER	NONE		start_chat
-SITTING			DIVIDE	NONE		start_gesture
-
-# Avatar editing camera controls
-EDIT_AVATAR		A		NONE		edit_avatar_spin_cw
-EDIT_AVATAR		D		NONE		edit_avatar_spin_ccw
-EDIT_AVATAR		W		NONE		edit_avatar_move_forward
-EDIT_AVATAR		S		NONE		edit_avatar_move_backward
-EDIT_AVATAR		E		NONE		edit_avatar_spin_over
-EDIT_AVATAR		C		NONE		edit_avatar_spin_under
-EDIT_AVATAR		LEFT	NONE		edit_avatar_spin_cw
-EDIT_AVATAR		RIGHT	NONE		edit_avatar_spin_ccw
-EDIT_AVATAR		UP		NONE		edit_avatar_move_forward
-EDIT_AVATAR		DOWN	NONE		edit_avatar_move_backward
-EDIT_AVATAR		PGUP	NONE		edit_avatar_spin_over
-EDIT_AVATAR		PGDN	NONE		edit_avatar_spin_under
-EDIT_AVATAR		ENTER	NONE		start_chat
-EDIT_AVATAR		DIVIDE	NONE		start_gesture
-EDIT_AVATAR		PAD_LEFT	NONE	edit_avatar_spin_cw
-EDIT_AVATAR		PAD_RIGHT	NONE	edit_avatar_spin_ccw
-EDIT_AVATAR		PAD_UP		NONE	edit_avatar_move_forward
-EDIT_AVATAR		PAD_DOWN	NONE	edit_avatar_move_backward
-EDIT_AVATAR		PAD_PGUP	NONE	edit_avatar_spin_over
-EDIT_AVATAR		PAD_PGDN	NONE	edit_avatar_spin_under
-EDIT_AVATAR		PAD_ENTER	NONE	start_chat
-EDIT_AVATAR		PAD_DIVIDE	NONE	start_gesture
diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp
index 570f372950..4e60c47f07 100644
--- a/indra/newview/llviewerkeyboard.cpp
+++ b/indra/newview/llviewerkeyboard.cpp
@@ -598,8 +598,7 @@ REGISTER_KEYBOARD_ACTION("stop_moving", stop_moving);
 REGISTER_KEYBOARD_ACTION("start_chat", start_chat);
 REGISTER_KEYBOARD_ACTION("start_gesture", start_gesture);
 
-LLViewerKeyboard::LLViewerKeyboard() :
-	mNamedFunctionCount(0)
+LLViewerKeyboard::LLViewerKeyboard()
 {
 	for (S32 i = 0; i < MODE_COUNT; i++)
 	{
@@ -617,16 +616,6 @@ LLViewerKeyboard::LLViewerKeyboard() :
 	}
 }
 
-
-void LLViewerKeyboard::bindNamedFunction(const std::string& name, LLKeyFunc func)
-{
-	S32 i = mNamedFunctionCount;
-	mNamedFunctions[i].mName = name;
-	mNamedFunctions[i].mFunction = func;
-	mNamedFunctionCount++;
-}
-
-
 BOOL LLViewerKeyboard::modeFromString(const std::string& string, S32 *mode)
 {
 	if (string == "FIRST_PERSON")
@@ -699,8 +688,9 @@ BOOL LLViewerKeyboard::handleKey(KEY translated_key,  MASK translated_mask, BOOL
 
 BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name)
 {
-	S32 i,index;
-	void (*function)(EKeystate keystate) = NULL;
+	S32 index;
+	typedef boost::function<void(EKeystate)> function_t;
+	function_t function = NULL;
 	std::string name;
 
 	// Allow remapping of F2-F12
@@ -723,13 +713,11 @@ BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, c
 	}
 
 	// Not remapped, look for a function
-	for (i = 0; i < mNamedFunctionCount; i++)
+	
+	function_t* result = LLKeyboardActionRegistry::getValue(function_name);
+	if (result)
 	{
-		if (function_name == mNamedFunctions[i].mName)
-		{
-			function = mNamedFunctions[i].mFunction;
-			name = mNamedFunctions[i].mName;
-		}
+		function = *result;
 	}
 
 	if (!function)
@@ -759,7 +747,6 @@ BOOL LLViewerKeyboard::bindKey(const S32 mode, const KEY key, const MASK mask, c
 
 	mBindings[mode][index].mKey = key;
 	mBindings[mode][index].mMask = mask;
-// 	mBindings[mode][index].mName = name;
 	mBindings[mode][index].mFunction = function;
 
 	if (index == mBindingCount[mode])
@@ -971,18 +958,18 @@ void LLViewerKeyboard::scanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_lev
 				if (key_down && !repeat)
 				{
 					// ...key went down this frame, call function
-					(*binding[i].mFunction)( KEYSTATE_DOWN );
+					binding[i].mFunction( KEYSTATE_DOWN );
 				}
 				else if (key_up)
 				{
 					// ...key went down this frame, call function
-					(*binding[i].mFunction)( KEYSTATE_UP );
+					binding[i].mFunction( KEYSTATE_UP );
 				}
 				else if (key_level)
 				{
 					// ...key held down from previous frame
 					// Not windows, just call the function.
-					(*binding[i].mFunction)( KEYSTATE_LEVEL );
+					binding[i].mFunction( KEYSTATE_LEVEL );
 				}//if
 			}//if
 		}//for
diff --git a/indra/newview/llviewerkeyboard.h b/indra/newview/llviewerkeyboard.h
index 6e758cc7b3..925244e89b 100644
--- a/indra/newview/llviewerkeyboard.h
+++ b/indra/newview/llviewerkeyboard.h
@@ -89,8 +89,6 @@ public:
 
 	BOOL			handleKey(KEY key, MASK mask, BOOL repeated);
 
-	void			bindNamedFunction(const std::string& name, LLKeyFunc func);
-
 	S32				loadBindings(const std::string& filename);										// returns number bound, 0 on error
 	S32				loadBindingsXML(const std::string& filename);										// returns number bound, 0 on error
 	EKeyboardMode	getMode();
@@ -103,9 +101,6 @@ private:
 	S32				loadBindingMode(const LLViewerKeyboard::KeyMode& keymode);
 	BOOL			bindKey(const S32 mode, const KEY key, const MASK mask, const std::string& function_name);
 
-	S32				mNamedFunctionCount;
-	LLNamedFunction	mNamedFunctions[MAX_NAMED_FUNCTIONS];
-
 	// Hold all the ugly stuff torn out to make LLKeyboard non-viewer-specific here
 	S32				mBindingCount[MODE_COUNT];
 	LLKeyBinding	mBindings[MODE_COUNT][MAX_KEY_BINDINGS];
-- 
cgit v1.2.3


From 1f7ff277d4e0d050f221e76c143f5101fb02d75f Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Thu, 30 Sep 2010 20:08:53 -0700
Subject: EXP-128 FIX Stand button displays partially offscreen

---
 indra/newview/llmoveview.cpp | 30 ++++++++++++++++++------------
 1 file changed, 18 insertions(+), 12 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp
index 6658e1d7e8..35c74d290b 100644
--- a/indra/newview/llmoveview.cpp
+++ b/indra/newview/llmoveview.cpp
@@ -448,17 +448,20 @@ void LLFloaterMove::updatePosition()
 	LLBottomTray* tray = LLBottomTray::getInstance();
 	if (!tray) return;
 
-	LLButton* movement_btn = tray->getChild<LLButton>(BOTTOM_TRAY_BUTTON_NAME);
+	LLButton* movement_btn = tray->findChild<LLButton>(BOTTOM_TRAY_BUTTON_NAME);
 
-	//align centers of a button and a floater
-	S32 x = movement_btn->calcScreenRect().getCenterX() - getRect().getWidth()/2;
-
-	S32 y = 0;
-	if (!mModeActionsPanel->getVisible())
+	if (movement_btn)
 	{
-		y = mModeActionsPanel->getRect().getHeight();
+		//align centers of a button and a floater
+		S32 x = movement_btn->calcScreenRect().getCenterX() - getRect().getWidth()/2;
+
+		S32 y = 0;
+		if (!mModeActionsPanel->getVisible())
+		{
+			y = mModeActionsPanel->getRect().getHeight();
+		}
+		setOrigin(x, y);
 	}
-	setOrigin(x, y);
 }
 
 //static
@@ -735,11 +738,14 @@ void LLPanelStandStopFlying::updatePosition()
 	LLBottomTray* tray = LLBottomTray::getInstance();
 	if (!tray || mAttached) return;
 
-	LLButton* movement_btn = tray->getChild<LLButton>(BOTTOM_TRAY_BUTTON_NAME);
+	LLButton* movement_btn = tray->findChild<LLButton>(BOTTOM_TRAY_BUTTON_NAME);
 
-	// Align centers of the button and the panel.
-	S32 x = movement_btn->calcScreenRect().getCenterX() - getRect().getWidth()/2;
-	setOrigin(x, 0);
+	if (movement_btn)
+	{
+		// Align centers of the button and the panel.
+		S32 x = movement_btn->calcScreenRect().getCenterX() - getRect().getWidth()/2;
+		setOrigin(x, 0);
+	}
 }
 
 
-- 
cgit v1.2.3


From 93faa08da9d8ebab516191f4b446e86d3c2800a2 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Thu, 30 Sep 2010 20:19:24 -0700
Subject: EXP-128 FIX Stand button displays partially offscreen

---
 indra/newview/llmoveview.cpp | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp
index 35c74d290b..f6b85de4b8 100644
--- a/indra/newview/llmoveview.cpp
+++ b/indra/newview/llmoveview.cpp
@@ -740,12 +740,17 @@ void LLPanelStandStopFlying::updatePosition()
 
 	LLButton* movement_btn = tray->findChild<LLButton>(BOTTOM_TRAY_BUTTON_NAME);
 
+	S32 x = 0;
 	if (movement_btn)
 	{
 		// Align centers of the button and the panel.
-		S32 x = movement_btn->calcScreenRect().getCenterX() - getRect().getWidth()/2;
-		setOrigin(x, 0);
+		x = movement_btn->calcScreenRect().getCenterX() - getRect().getWidth()/2;
+	}
+	else
+	{
+		x = tray->calcScreenRect().getCenterX() - getRect().getWidth()/2;
 	}
+	setOrigin(x, 0);
 }
 
 
-- 
cgit v1.2.3


From d6ca1ef033a8c2f32ec9322b30eb28de305e612f Mon Sep 17 00:00:00 2001
From: callum <none@none>
Date: Fri, 1 Oct 2010 10:17:58 -0700
Subject: Keys.xml replaces keys.ini - fix for CMake

---
 indra/newview/CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 1f4302d870..074fa6397d 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1314,7 +1314,7 @@ set(viewer_APPSETTINGS_FILES
     app_settings/grass.xml
     app_settings/high_graphics.xml
     app_settings/ignorable_dialogs.xml
-    app_settings/keys.ini
+    app_settings/keys.xml
     app_settings/keywords.ini
     app_settings/logcontrol.xml
     app_settings/low_graphics.xml
-- 
cgit v1.2.3


From e6493c7abea645b6d8394b3f03b59a59378ad986 Mon Sep 17 00:00:00 2001
From: Monroe Linden <monroe@lindenlab.com>
Date: Fri, 1 Oct 2010 14:00:27 -0700
Subject: Updated keys in notifications.xml to match current spec.

---
 .../newview/skins/default/xui/en/notifications.xml | 25 ++++++++++++++++++++++
 1 file changed, 25 insertions(+)

(limited to 'indra/newview')

diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 7dd7cefa5d..cf5a6ad255 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -441,6 +441,7 @@ Please invite members within 48 hours.
    icon="alertmodal.tga"
    name="LandBuyPass"
    type="alertmodal">
+   <tag>fail</tag>
 For L$[COST] you can enter this land (&apos;[PARCEL_NAME]&apos;) for [TIME] hours.  Buy a pass?
     <usetemplate
      name="okcancelbuttons"
@@ -1589,6 +1590,7 @@ If you continue to get this message, please check the [SUPPORT_SITE].
    icon="alertmodal.tga"
    name="blocked_tport"
    type="alertmodal">
+   <tag>fail</tag>
 Sorry, teleport is currently blocked. Try again in a moment.  If you still cannot teleport, please log out and log back in to resolve the problem.
   </notification>
   <notification
@@ -1601,42 +1603,49 @@ Sorry, but system was unable to locate landmark destination.
    icon="alertmodal.tga"
    name="timeout_tport"
    type="alertmodal">
+   <tag>fail</tag>
 Sorry, but system was unable to complete the teleport connection.  Try again in a moment.
   </notification>
   <notification
    icon="alertmodal.tga"
    name="noaccess_tport"
    type="alertmodal">
+   <tag>fail</tag>
 Sorry, you do not have access to that teleport destination.
   </notification>
   <notification
    icon="alertmodal.tga"
    name="missing_attach_tport"
    type="alertmodal">
+   <tag>fail</tag>
 Your attachments have not arrived yet. Try waiting for a few more seconds or log out and back in again before attempting to teleport.
   </notification>
   <notification
    icon="alertmodal.tga"
    name="too_many_uploads_tport"
    type="alertmodal">
+   <tag>fail</tag>
 The asset queue in this region is currently clogged so your teleport request will not be able to succeed in a timely manner. Please try again in a few minutes or go to a less busy area.
   </notification>
   <notification
    icon="alertmodal.tga"
    name="expired_tport"
    type="alertmodal">
+   <tag>fail</tag>
 Sorry, but the system was unable to complete your teleport request in a timely fashion. Please try again in a few minutes.
   </notification>
   <notification
    icon="alertmodal.tga"
    name="expired_region_handoff"
    type="alertmodal">
+   <tag>fail</tag>
 Sorry, but the system was unable to complete your region crossing in a timely fashion. Please try again in a few minutes.
   </notification>
   <notification
    icon="alertmodal.tga"
    name="no_host"
    type="alertmodal">
+   <tag>fail</tag>
 Unable to find teleport destination. The destination may be temporarily unavailable or no longer exists. Please try again in a few minutes.
   </notification>
   <notification
@@ -2418,6 +2427,7 @@ Display settings have been set to recommended levels based on your system config
    icon="alertmodal.tga"
    name="AvatarMovedDesired"
    type="alertmodal">
+   <tag>fail</tag>
 Your desired location is not currently available.
 You have been moved into a nearby region.
   </notification>
@@ -2426,6 +2436,7 @@ You have been moved into a nearby region.
    icon="alertmodal.tga"
    name="AvatarMovedLast"
    type="alertmodal">
+   <tag>fail</tag>
 Your last location is not currently available.
 You have been moved into a nearby region.
   </notification>
@@ -2434,6 +2445,7 @@ You have been moved into a nearby region.
    icon="alertmodal.tga"
    name="AvatarMovedHome"
    type="alertmodal">
+   <tag>fail</tag>
 Your home location is not currently available.
 You have been moved into a nearby region.
 You may want to set a new home location.
@@ -2443,6 +2455,7 @@ You may want to set a new home location.
    icon="alertmodal.tga"
    name="ClothingLoading"
    type="alertmodal">
+   <tag>fail</tag>
 Your clothing is still downloading.
 You can use [SECOND_LIFE] normally and other people will see you correctly.
     <form name="form">
@@ -2470,6 +2483,7 @@ Return to [http://join.secondlife.com secondlife.com] to create a new account?
    icon="alertmodal.tga"
    name="LoginPacketNeverReceived"
    type="alertmodal">
+   <tag>fail</tag>
 We&apos;re having trouble connecting. There may be a problem with your Internet connection or the [SECOND_LIFE_GRID].
 
 You can either check your Internet connection and try again in a few minutes, click Help to view the [SUPPORT_SITE], or click Teleport to attempt to teleport home.
@@ -3474,6 +3488,7 @@ Are you sure you want to change the Estate Covenant?
    icon="alertmodal.tga"
    name="RegionEntryAccessBlocked"
    type="alertmodal">
+   <tag>fail</tag>
 You are not allowed in that Region due to your maturity Rating. This may be a result of a lack of information validating your age.
 
 Please verify you have the latest Viewer installed, and go to the Knowledge Base for details on accessing areas with this maturity rating.
@@ -3486,6 +3501,7 @@ Please verify you have the latest Viewer installed, and go to the Knowledge Base
    icon="alertmodal.tga"
    name="RegionEntryAccessBlocked_KB"
    type="alertmodal">
+   <tag>fail</tag>
 You are not allowed in that region due to your maturity Rating.
 
 Go to the Knowledge Base for more information about maturity Ratings?
@@ -3503,6 +3519,7 @@ Go to the Knowledge Base for more information about maturity Ratings?
    icon="notifytip.tga"
    name="RegionEntryAccessBlocked_Notify"
    type="notifytip">
+   <tag>fail</tag>
 You are not allowed in that region due to your maturity Rating.
   </notification>
 
@@ -3510,6 +3527,7 @@ You are not allowed in that region due to your maturity Rating.
    icon="alertmodal.tga"
    name="RegionEntryAccessBlocked_Change"
    type="alertmodal">
+   <tag>fail</tag>
 You are not allowed in that Region due to your maturity Rating preference.
 
 To enter the desired region, please change your maturity Rating preference. This will allow you to search for and access [REGIONMATURITY] content. To undo any changes, go to Me &gt; Preferences &gt; General.
@@ -4426,6 +4444,7 @@ Would you like to automatically wear the clothing you are about to create?
    icon="alertmodal.tga"
    name="NotAgeVerified"
    type="alertmodal">
+   <tag>fail</tag>
 You must be age-verified to visit this area.  Do you want to go to the [SECOND_LIFE] website and verify your age?
 
 [_URL]
@@ -4980,6 +4999,7 @@ You can be hurt here. If you die, you will be teleported to your home location.
    persist="true"
    type="notify"
    unique="true">
+   <tag>fail</tag>
 This area has flying disabled.
 You can&apos;t fly here.
   </notification>
@@ -5032,6 +5052,7 @@ This region is not running any scripts.
    name="NoOutsideScripts"
    persist="true"
    type="notify">
+   <tag>fail</tag>
 This land has outside scripts disabled.
 
 No scripts will work here except those belonging to the land owner.
@@ -5133,6 +5154,7 @@ Cannot region cross into banned parcel. Try another way.
 	name="TelehubRedirect"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 You have been redirected to a telehub.
   </notification>
 
@@ -6064,6 +6086,7 @@ New Voice Morphs are available!
    icon="notifytip.tga"
    name="Cannot enter parcel: not a group member"
    type="notifytip">
+   <tag>fail</tag>
 Only members of a certain group can visit this area.
   </notification>
 
@@ -6071,6 +6094,7 @@ Only members of a certain group can visit this area.
    icon="notifytip.tga"
    name="Cannot enter parcel: banned"
    type="notifytip">
+   <tag>fail</tag>
 Cannot enter parcel, you have been banned.
   </notification>
 
@@ -6078,6 +6102,7 @@ Cannot enter parcel, you have been banned.
    icon="notifytip.tga"
    name="Cannot enter parcel: not on access list"
    type="notifytip">
+   <tag>fail</tag>
 Cannot enter parcel, you are not on the access list.
   </notification>
 
-- 
cgit v1.2.3


From 033c45f99024dd8197a94936443f67f3e76d40bb Mon Sep 17 00:00:00 2001
From: Richard Nelson <none@none>
Date: Mon, 4 Oct 2010 11:21:15 -0700
Subject: EXP-142 FIXED Disable mouselook in Skylight

---
 indra/newview/app_settings/settings.xml | 11 +++++++++++
 indra/newview/llagentcamera.cpp         |  2 +-
 indra/newview/llviewerkeyboard.cpp      |  1 +
 3 files changed, 13 insertions(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 18a064c7ba..b24de89103 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -2842,6 +2842,17 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
+    <key>EnableMouselook</key>
+    <map>
+      <key>Comment</key>
+      <string>Allow first person perspective and mouse control of camera</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
     <key>EnableRippleWater</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index 68e408d3e4..e7fee26dc5 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -2038,7 +2038,7 @@ void LLAgentCamera::resetCamera()
 //-----------------------------------------------------------------------------
 void LLAgentCamera::changeCameraToMouselook(BOOL animate)
 {
-	if (LLViewerJoystick::getInstance()->getOverrideCamera())
+	if (!gSavedSettings.getBOOL("EnableMouselook") || LLViewerJoystick::getInstance()->getOverrideCamera())
 	{
 		return;
 	}
diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp
index 4e60c47f07..1aa9fd8a45 100644
--- a/indra/newview/llviewerkeyboard.cpp
+++ b/indra/newview/llviewerkeyboard.cpp
@@ -597,6 +597,7 @@ REGISTER_KEYBOARD_ACTION("edit_avatar_move_backward", edit_avatar_move_backward)
 REGISTER_KEYBOARD_ACTION("stop_moving", stop_moving);
 REGISTER_KEYBOARD_ACTION("start_chat", start_chat);
 REGISTER_KEYBOARD_ACTION("start_gesture", start_gesture);
+#undef REGISTER_KEYBOARD_ACTION
 
 LLViewerKeyboard::LLViewerKeyboard()
 {
-- 
cgit v1.2.3


From 6e471d395fdec324164469e54613ae9bf30e1e9f Mon Sep 17 00:00:00 2001
From: Richard Nelson <none@none>
Date: Mon, 4 Oct 2010 16:38:03 -0700
Subject: removed dead code

---
 indra/newview/llhudtext.cpp | 3 ---
 1 file changed, 3 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp
index 96638018c4..99a0da8b01 100644
--- a/indra/newview/llhudtext.cpp
+++ b/indra/newview/llhudtext.cpp
@@ -326,9 +326,6 @@ void LLHUDText::renderText(BOOL for_select)
 
 	mRadius = (width_vec + height_vec).magVec() * 0.5f;
 
-	LLCoordGL screen_pos;
-	LLViewerCamera::getInstance()->projectPosAgentToScreen(mPositionAgent, screen_pos, FALSE);
-
 	LLVector2 screen_offset;
 	if (!mUseBubble)
 	{
-- 
cgit v1.2.3


From 5e0e86869dcb0c365c486776f8dacba14a029d1e Mon Sep 17 00:00:00 2001
From: Richard Nelson <none@none>
Date: Mon, 4 Oct 2010 18:38:38 -0700
Subject: EXP-138 WIP Chat and IM notices not aligned with Bottom bar in
 Skylight Viewer

---
 indra/newview/llnearbychathandler.cpp | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp
index 47d32e57fb..f06f4eab28 100644
--- a/indra/newview/llnearbychathandler.cpp
+++ b/indra/newview/llnearbychathandler.cpp
@@ -336,7 +336,12 @@ void LLNearbyChatScreenChannel::showToastsBottom()
 		return;
 
 	LLRect	toast_rect;	
-	S32		bottom = getRect().mBottom;
+	S32 channel_bottom = gViewerWindow->getWorldViewRectScaled().mBottom + gSavedSettings.getS32("ChannelBottomPanelMargin");
+	LLRect cur_rect = getRect();
+	cur_rect.translate(0, channel_bottom - cur_rect.mBottom);
+	setRect(cur_rect);
+
+	S32		bottom = channel_bottom;
 	S32		margin = gSavedSettings.getS32("ToastGap");
 
 	//sort active toasts
-- 
cgit v1.2.3


From 52d3f86438925d5d9509d93b162ea8915e1caad7 Mon Sep 17 00:00:00 2001
From: Richard Nelson <none@none>
Date: Mon, 4 Oct 2010 18:39:09 -0700
Subject: fixed merging of textures.xml between current skin and base now
 possible to define new textures in current skin

---
 indra/newview/llviewertexturelist.cpp | 74 ++++++++++++++++++-----------------
 1 file changed, 39 insertions(+), 35 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index bbf7c8e60e..06c218ad94 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -1513,42 +1513,45 @@ bool LLUIImageList::initFromFile()
 		return false;
 	}
 
-	std::vector<std::string> paths;
-	// path to current selected skin
-	paths.push_back(gDirUtilp->getSkinDir() 
-			+ gDirUtilp->getDirDelimiter() 
-			+ "textures"
-			+ gDirUtilp->getDirDelimiter()
-			+ "textures.xml");
-	// path to user overrides on current skin
-	paths.push_back(gDirUtilp->getUserSkinDir() 
-			+ gDirUtilp->getDirDelimiter() 
-			+ "textures"
-			+ gDirUtilp->getDirDelimiter()
-			+ "textures.xml");
-
-	// apply skinned xml files incrementally
-	for(std::vector<std::string>::iterator path_it = paths.begin();
-		path_it != paths.end();
-		++path_it)
-	{
-		// don't reapply base file to itself
-		if (!path_it->empty() && (*path_it) != base_file_path)
-		{
-			LLXMLNodePtr update_root;
-			if (LLXMLNode::parseFile(*path_it, update_root, NULL))
-			{
-				LLXMLNode::updateNode(root, update_root);
-			}
-		}
-	}
-
 	UIImageDeclarations images;
 	LLXUIParser parser;
 	parser.readXUI(root, images, base_file_path);
 
+	// add components defined in current skin
+	std::string skin_update_path = gDirUtilp->getSkinDir() 
+									+ gDirUtilp->getDirDelimiter() 
+									+ "textures"
+									+ gDirUtilp->getDirDelimiter()
+									+ "textures.xml";
+	LLXMLNodePtr update_root;
+	if (skin_update_path != base_file_path
+		&& LLXMLNode::parseFile(skin_update_path, update_root, NULL))
+	{
+		parser.readXUI(update_root, images, skin_update_path);
+	}
+
+	// add components defined in user override of current skin
+	skin_update_path = gDirUtilp->getUserSkinDir() 
+						+ gDirUtilp->getDirDelimiter() 
+						+ "textures"
+						+ gDirUtilp->getDirDelimiter()
+						+ "textures.xml";
+	if (skin_update_path != base_file_path
+		&& LLXMLNode::parseFile(skin_update_path, update_root, NULL))
+	{
+		parser.readXUI(update_root, images, skin_update_path);
+	}
+
 	if (!images.validateBlock()) return false;
 
+	std::map<std::string, UIImageDeclaration> merged_declarations;
+	for (LLInitParam::ParamIterator<UIImageDeclaration>::const_iterator image_it = images.textures.begin();
+		image_it != images.textures.end();
+		++image_it)
+	{
+		merged_declarations[image_it->name].overwriteFrom(*image_it);
+	}
+
 	enum e_decode_pass
 	{
 		PASS_DECODE_NOW,
@@ -1558,19 +1561,20 @@ bool LLUIImageList::initFromFile()
 
 	for (S32 cur_pass = PASS_DECODE_NOW; cur_pass < NUM_PASSES; cur_pass++)
 	{
-		for (LLInitParam::ParamIterator<UIImageDeclaration>::const_iterator image_it = images.textures.begin();
-			image_it != images.textures.end();
+		for (std::map<std::string, UIImageDeclaration>::const_iterator image_it = merged_declarations.begin();
+			image_it != merged_declarations.end();
 			++image_it)
 		{
-			std::string file_name = image_it->file_name.isProvided() ? image_it->file_name() : image_it->name();
+			const UIImageDeclaration& image = image_it->second;
+			std::string file_name = image.file_name.isProvided() ? image.file_name() : image.name();
 
 			// load high priority textures on first pass (to kick off decode)
-			enum e_decode_pass decode_pass = image_it->preload ? PASS_DECODE_NOW : PASS_DECODE_LATER;
+			enum e_decode_pass decode_pass = image.preload ? PASS_DECODE_NOW : PASS_DECODE_LATER;
 			if (decode_pass != cur_pass)
 			{
 				continue;
 			}
-			preloadUIImage(image_it->name, file_name, image_it->use_mips, image_it->scale);
+			preloadUIImage(image.name, file_name, image.use_mips, image.scale);
 		}
 
 		if (cur_pass == PASS_DECODE_NOW && !gSavedSettings.getBOOL("NoPreload"))
-- 
cgit v1.2.3


From 3081f89744ab527af4c843bdf898654d4ba87b57 Mon Sep 17 00:00:00 2001
From: Richard Nelson <none@none>
Date: Mon, 4 Oct 2010 19:07:28 -0700
Subject: EXP-138 FIXED Chat and IM notices not aligned with Bottom bar in
 Skylight Viewer

---
 indra/newview/llnearbychathandler.cpp |  6 ++----
 indra/newview/llscreenchannel.cpp     | 22 ++++++++++++++--------
 indra/newview/llscreenchannel.h       |  2 ++
 3 files changed, 18 insertions(+), 12 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp
index f06f4eab28..adb79fd4fd 100644
--- a/indra/newview/llnearbychathandler.cpp
+++ b/indra/newview/llnearbychathandler.cpp
@@ -336,10 +336,8 @@ void LLNearbyChatScreenChannel::showToastsBottom()
 		return;
 
 	LLRect	toast_rect;	
-	S32 channel_bottom = gViewerWindow->getWorldViewRectScaled().mBottom + gSavedSettings.getS32("ChannelBottomPanelMargin");
-	LLRect cur_rect = getRect();
-	cur_rect.translate(0, channel_bottom - cur_rect.mBottom);
-	setRect(cur_rect);
+	updateBottom();
+	S32 channel_bottom = getRect().mBottom;
 
 	S32		bottom = channel_bottom;
 	S32		margin = gSavedSettings.getS32("ToastGap");
diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp
index 5c923a0409..b90ff80294 100644
--- a/indra/newview/llscreenchannel.cpp
+++ b/indra/newview/llscreenchannel.cpp
@@ -136,12 +136,22 @@ void LLScreenChannelBase::init(S32 channel_left, S32 channel_right)
 		side_bar->getCollapseSignal().connect(boost::bind(&LLScreenChannelBase::resetPositionAndSize, this, _2));
 	}
 
+	// top and bottom set by updateBottom()
+	setRect(LLRect(channel_left, 0, channel_right, 0));
+	updateBottom();
+	setVisible(TRUE);
+}
+
+void	LLScreenChannelBase::updateBottom()
+{
 	S32 channel_top = gViewerWindow->getWorldViewRectScaled().getHeight();
 	S32 channel_bottom = gViewerWindow->getWorldViewRectScaled().mBottom + gSavedSettings.getS32("ChannelBottomPanelMargin");
+	S32 channel_left = getRect().mLeft;
+	S32 channel_right = getRect().mRight;
 	setRect(LLRect(channel_left, channel_top, channel_right, channel_bottom));
-	setVisible(TRUE);
 }
 
+
 //--------------------------------------------------------------------------
 //////////////////////
 // LLScreenChannel
@@ -512,6 +522,8 @@ void LLScreenChannel::showToastsBottom()
 	S32		toast_margin = 0;
 	std::vector<ToastElem>::reverse_iterator it;
 
+	updateBottom();
+
 	LLDockableFloater* floater = dynamic_cast<LLDockableFloater*>(LLDockableFloater::getInstanceHandle().get());
 
 	for(it = mToastList.rbegin(); it != mToastList.rend(); ++it)
@@ -866,13 +878,7 @@ void LLScreenChannel::updateShowToastsState()
 		return;
 	}
 
-	S32 channel_bottom = gViewerWindow->getWorldViewRectScaled().mBottom + gSavedSettings.getS32("ChannelBottomPanelMargin");;
-	LLRect this_rect = getRect();
-
-	if(channel_bottom != this_rect.mBottom)
-	{
-		setRect(LLRect(this_rect.mLeft, this_rect.mTop, this_rect.mRight, channel_bottom));
-	}
+	updateBottom();
 }
 
 //--------------------------------------------------------------------------
diff --git a/indra/newview/llscreenchannel.h b/indra/newview/llscreenchannel.h
index 6cf6d97550..62f822458b 100644
--- a/indra/newview/llscreenchannel.h
+++ b/indra/newview/llscreenchannel.h
@@ -111,6 +111,8 @@ public:
 	LLUUID	getChannelID() { return mID; }
 
 protected:
+	void	updateBottom();
+
 	// Channel's flags
 	bool		mControlHovering;
 	LLToast*		mHoveredToast;
-- 
cgit v1.2.3


From ff81c6c529ce2c7216ee2cd5aa60b7a232792fec Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Tue, 5 Oct 2010 14:31:07 -0700
Subject: changed format of notification_visibility rules to be cleaner

---
 indra/newview/skins/default/xui/en/notification_visibility.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/skins/default/xui/en/notification_visibility.xml b/indra/newview/skins/default/xui/en/notification_visibility.xml
index cb36890fe6..ea32a83b83 100644
--- a/indra/newview/skins/default/xui/en/notification_visibility.xml
+++ b/indra/newview/skins/default/xui/en/notification_visibility.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" ?>
 <notification_visibility>
-	<rule visible="true"/> 
+	<show/> 
 </notification_visibility>
 
-- 
cgit v1.2.3


From b285fd4d0abf9113fc416c30ac115db06c9f2ebf Mon Sep 17 00:00:00 2001
From: Monroe Linden <monroe@lindenlab.com>
Date: Tue, 5 Oct 2010 16:42:24 -0700
Subject: Fix for EXP-131 "Call dialog shown in locked position when a Resident
 calls a Skylight visitor"

Added the setting VoiceCallsRejectAll, which causes the viewer to silently reject all incoming voice calls.

Reviewed by Callum.
---
 indra/newview/app_settings/settings.xml | 11 +++++++++++
 indra/newview/llimview.cpp              | 21 ++++++++++-----------
 2 files changed, 21 insertions(+), 11 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 04d1137ac8..09f74e5508 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -11410,6 +11410,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>VoiceCallsRejectAll</key>
+    <map>
+      <key>Comment</key>
+      <string>Silently reject all incoming voice calls.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>VoiceDisableMic</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 01e1c3caa0..6b4e1f7289 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -2571,17 +2571,16 @@ void LLIMMgr::inviteToSession(
 
 	if (type == IM_SESSION_P2P_INVITE || ad_hoc_invite)
 	{
-		// is the inviter a friend?
-		if (LLAvatarTracker::instance().getBuddyInfo(caller_id) == NULL)
-		{
-			// if not, and we are ignoring voice invites from non-friends
-			// then silently decline
-			if (gSavedSettings.getBOOL("VoiceCallsFriendsOnly"))
-			{
-				// invite not from a friend, so decline
-				LLNotifications::instance().forceResponse(LLNotification::Params("VoiceInviteP2P").payload(payload), 1);
-				return;
-			}
+			
+		if	(	// if we're rejecting all incoming call requests
+				gSavedSettings.getBOOL("VoiceCallsRejectAll")	
+				// or we're rejecting non-friend voice calls and this isn't a friend	
+				|| (gSavedSettings.getBOOL("VoiceCallsFriendsOnly") && (LLAvatarTracker::instance().getBuddyInfo(caller_id) == NULL))
+			)
+		{
+			// silently decline the call
+			LLNotifications::instance().forceResponse(LLNotification::Params("VoiceInviteP2P").payload(payload), 1);
+			return;
 		}
 	}
 
-- 
cgit v1.2.3


From f5b3fc596d029d3ac2f953ee94ea3ae131d00940 Mon Sep 17 00:00:00 2001
From: callum <none@none>
Date: Wed, 6 Oct 2010 15:34:32 -0700
Subject: Add support for debug setting to disable link highlight & follow in
 URLs that appear in XUI widgets

---
 indra/newview/app_settings/settings.xml | 11 +++++++++++
 1 file changed, 11 insertions(+)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 09f74e5508..345a1f3576 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -2556,6 +2556,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>DisableTextHyperlinkActions</key>
+    <map>
+      <key>Comment</key>
+      <string>Disable highlighting and linking of URLs in XUI text boxes</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>DisableVerticalSync</key>
     <map>
       <key>Comment</key>
-- 
cgit v1.2.3


From f974a019b19a68fee219eb1b4e80d6dc5c5df92e Mon Sep 17 00:00:00 2001
From: Monroe Linden <monroe@lindenlab.com>
Date: Wed, 6 Oct 2010 16:50:04 -0700
Subject: Added DisableExternalBrowser setting.

Reviewed by Callum.
---
 indra/newview/app_settings/settings.xml | 11 +++++++++++
 indra/newview/llweb.cpp                 |  7 +++++++
 2 files changed, 18 insertions(+)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 345a1f3576..204097769a 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -2545,6 +2545,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>DisableExternalBrowser</key>
+    <map>
+      <key>Comment</key>
+      <string>Disable opening an external browser.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>DisableRendering</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp
index 73a37a6993..6028a8fbea 100644
--- a/indra/newview/llweb.cpp
+++ b/indra/newview/llweb.cpp
@@ -116,6 +116,13 @@ void LLWeb::loadURLExternal(const std::string& url, bool async, const std::strin
 	// Act like the proxy window was closed, since we won't be able to track targeted windows in the external browser.
 	LLViewerMedia::proxyWindowClosed(uuid);
 	
+	if(gSavedSettings.getBOOL("DisableExternalBrowser"))
+	{
+		// Don't open an external browser under any circumstances.
+		llwarns << "Blocked attempt to open external browser." << llendl;
+		return;
+	}
+	
 	LLSD payload;
 	payload["url"] = url;
 	LLNotificationsUtil::add( "WebLaunchExternalTarget", LLSD(), payload, boost::bind(on_load_url_external_response, _1, _2, async));
-- 
cgit v1.2.3


From 01b28ddf5ddc7118bc8b2047d899aee0293a8721 Mon Sep 17 00:00:00 2001
From: Richard Nelson <none@none>
Date: Wed, 6 Oct 2010 20:10:36 -0700
Subject: EXP-156 WIP Implement custom Skylight hints

---
 indra/newview/app_settings/ignorable_dialogs.xml   |  11 ++++
 indra/newview/app_settings/settings.xml            |   2 +-
 indra/newview/llbottomtray.cpp                     |   1 +
 indra/newview/llfirstuse.cpp                       |  11 +++-
 indra/newview/llfirstuse.h                         |   1 +
 indra/newview/llfloatercamera.cpp                  |   5 ++
 indra/newview/llhints.cpp                          |  15 ++++-
 indra/newview/llnearbychathandler.cpp              |  16 ++---
 indra/newview/llpanelplaces.cpp                    |   2 -
 indra/newview/llpopupview.cpp                      |  70 ++++++++++++++++-----
 indra/newview/llrootview.h                         |  22 -------
 indra/newview/llsidetray.cpp                       |   1 -
 indra/newview/lltransientfloatermgr.cpp            |   4 +-
 indra/newview/llviewermenu.cpp                     |   3 +-
 .../newview/skins/default/textures/arrow_keys.png  | Bin 0 -> 6558 bytes
 .../newview/skins/default/xui/en/notifications.xml |  16 +++++
 .../skins/default/xui/en/panel_hint_image.xml      |  39 ++++++++++++
 17 files changed, 163 insertions(+), 56 deletions(-)
 create mode 100644 indra/newview/skins/default/textures/arrow_keys.png
 create mode 100644 indra/newview/skins/default/xui/en/panel_hint_image.xml

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/ignorable_dialogs.xml b/indra/newview/app_settings/ignorable_dialogs.xml
index 0720ccee49..f800d836fa 100644
--- a/indra/newview/app_settings/ignorable_dialogs.xml
+++ b/indra/newview/app_settings/ignorable_dialogs.xml
@@ -45,6 +45,17 @@
     <key>Value</key>
     <integer>1</integer>
   </map>
+  <key>FirstViewPopup</key>
+  <map>
+    <key>Comment</key>
+    <string>Shows hint when resident opens view popup</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>1</integer>
+  </map>
   <key>FirstReceiveLindens</key>
   <map>
     <key>Comment</key>
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 204097769a..d5cfc11c2c 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -12176,7 +12176,7 @@
       <key>Type</key>
       <string>F32</string>
       <key>Value</key>
-      <real>600.0</real>
+      <real>1200.0</real>
     </map>
     <key>SidePanelHintTimeout</key>
     <map>
diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp
index e47009c540..d869850b7c 100644
--- a/indra/newview/llbottomtray.cpp
+++ b/indra/newview/llbottomtray.cpp
@@ -517,6 +517,7 @@ void LLBottomTray::toggleCameraControls()
 
 BOOL LLBottomTray::postBuild()
 {
+	LLHints::registerHintTarget("dest_guide_btn", getChild<LLUICtrl>("destinations_btn")->getHandle());
 
 	LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("NearbyChatBar.Action", boost::bind(&LLBottomTray::onContextMenuItemClicked, this, _2));
 	LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("NearbyChatBar.EnableMenuItem", boost::bind(&LLBottomTray::onContextMenuItemEnabled, this, _2));
diff --git a/indra/newview/llfirstuse.cpp b/indra/newview/llfirstuse.cpp
index dd08706f4f..4d6302596b 100644
--- a/indra/newview/llfirstuse.cpp
+++ b/indra/newview/llfirstuse.cpp
@@ -100,7 +100,7 @@ void LLFirstUse::useSandbox()
 void LLFirstUse::notUsingDestinationGuide(bool enable)
 {
 	// not doing this yet
-	//firstUseNotification("FirstNotUseDestinationGuide", enable, "HintDestinationGuide", LLSD(), LLSD().with("target", "dest_guide_btn").with("direction", "left"));
+	firstUseNotification("FirstNotUseDestinationGuide", enable, "HintDestinationGuide", LLSD(), LLSD().with("target", "dest_guide_btn").with("direction", "top"));
 }
 
 // static
@@ -113,7 +113,14 @@ void LLFirstUse::notUsingSidePanel(bool enable)
 // static
 void LLFirstUse::notMoving(bool enable)
 {
-	firstUseNotification("FirstNotMoving", enable, "HintMove", LLSD(), LLSD().with("target", "move_btn").with("direction", "top"));
+	//firstUseNotification("FirstNotMoving", enable, "HintMove", LLSD(), LLSD().with("target", "move_btn").with("direction", "top"));
+	firstUseNotification("FirstNotMoving", enable, "HintMoveArrows", LLSD(), LLSD().with("hint_image", "arrow_keys.png"));
+}
+
+// static
+void LLFirstUse::viewPopup(bool enable)
+{
+	firstUseNotification("FirstViewPopup", enable, "HintView", LLSD(), LLSD().with("target", "view_popup").with("direction", "right"));
 }
 
 // static
diff --git a/indra/newview/llfirstuse.h b/indra/newview/llfirstuse.h
index 275f134400..3886df4ee9 100644
--- a/indra/newview/llfirstuse.h
+++ b/indra/newview/llfirstuse.h
@@ -89,6 +89,7 @@ public:
 	static void notUsingDestinationGuide(bool enable = true);
 	static void notUsingSidePanel(bool enable = true);
 	static void notMoving(bool enable = true);
+	static void viewPopup(bool enable = true);
 	static void newInventory(bool enable = true);
 	static void receiveLindens(bool enable = true);
 	static void useSandbox();
diff --git a/indra/newview/llfloatercamera.cpp b/indra/newview/llfloatercamera.cpp
index b4e211a38e..be65396b0f 100644
--- a/indra/newview/llfloatercamera.cpp
+++ b/indra/newview/llfloatercamera.cpp
@@ -40,6 +40,8 @@
 #include "lltoolmgr.h"
 #include "lltoolfocus.h"
 #include "llslider.h"
+#include "llfirstuse.h"
+#include "llhints.h"
 
 static LLDefaultChildRegistry::Register<LLPanelCameraItem> r("panel_camera_item");
 
@@ -294,6 +296,8 @@ LLFloaterCamera* LLFloaterCamera::findInstance()
 
 void LLFloaterCamera::onOpen(const LLSD& key)
 {
+	LLFirstUse::viewPopup();
+
 	LLButton *anchor_panel = LLBottomTray::getInstance()->getChild<LLButton>("camera_btn");
 
 	setDockControl(new LLDockControl(
@@ -339,6 +343,7 @@ LLFloaterCamera::LLFloaterCamera(const LLSD& val)
 	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
 	registrar.add("CameraPresets.ChangeView", boost::bind(&LLFloaterCamera::onClickCameraItem, _2));
 
+	LLHints::registerHintTarget("view_popup", LLView::getHandle());
 }
 
 // virtual
diff --git a/indra/newview/llhints.cpp b/indra/newview/llhints.cpp
index d837ed8205..5ffc4ace59 100644
--- a/indra/newview/llhints.cpp
+++ b/indra/newview/llhints.cpp
@@ -33,6 +33,7 @@
 #include "lltextbox.h"
 #include "llviewerwindow.h"
 #include "llviewercontrol.h"
+#include "lliconctrl.h"
 #include "llsdparam.h"
 
 class LLHintPopup : public LLPanel
@@ -80,7 +81,8 @@ public:
 										up_arrow,
 										right_arrow,
 										down_arrow,
-										lower_left_arrow;
+										lower_left_arrow,
+										hint_image;
 				
 		Optional<S32>					left_arrow_offset,
 										up_arrow_offset,
@@ -96,6 +98,7 @@ public:
 			right_arrow("right_arrow"),
 			down_arrow("down_arrow"),
 			lower_left_arrow("lower_left_arrow"),
+			hint_image("hint_image"),
 			left_arrow_offset("left_arrow_offset"),
 			up_arrow_offset("up_arrow_offset"),
 			right_arrow_offset("right_arrow_offset"),
@@ -159,7 +162,15 @@ LLHintPopup::LLHintPopup(const LLHintPopup::Params& p)
 		mDirection = p.target_params.direction;
 		mTarget = p.target_params.target;
 	}
-	buildFromFile( "panel_hint.xml", NULL, p);
+	if (p.hint_image.isProvided())
+	{
+		buildFromFile("panel_hint_image.xml", NULL, p);
+		getChild<LLIconCtrl>("hint_image")->setImage(p.hint_image());
+	}
+	else
+	{
+		buildFromFile( "panel_hint.xml", NULL, p);
+	}
 }
 
 BOOL LLHintPopup::postBuild()
diff --git a/indra/newview/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp
index adb79fd4fd..7ee9aac0de 100644
--- a/indra/newview/llnearbychathandler.cpp
+++ b/indra/newview/llnearbychathandler.cpp
@@ -471,6 +471,14 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, const LLSD &args)
 	}
 
 	nearby_chat->addMessage(chat_msg, true, args);
+
+	if(chat_msg.mSourceType == CHAT_SOURCE_AGENT 
+		&& chat_msg.mFromID.notNull() 
+		&& chat_msg.mFromID != gAgentID)
+	{
+ 		LLFirstUse::otherAvatarChatFirst();
+	}
+
 	if( nearby_chat->getVisible()
 		|| ( chat_msg.mSourceType == CHAT_SOURCE_AGENT
 			&& gSavedSettings.getBOOL("UseChatBubbles") ) )
@@ -530,13 +538,7 @@ void LLNearbyChatHandler::processChat(const LLChat& chat_msg, const LLSD &args)
 		notification["font_size"] = (S32)LLViewerChat::getChatFontSize() ;
 		channel->addNotification(notification);	
 	}
-	
-	if(chat_msg.mSourceType == CHAT_SOURCE_AGENT 
-		&& chat_msg.mFromID.notNull() 
-		&& chat_msg.mFromID != gAgentID)
-	{
- 		LLFirstUse::otherAvatarChatFirst();
-	}
+
 }
 
 void LLNearbyChatHandler::onDeleteToast(LLToast* toast)
diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp
index f0e60386b6..8884228f23 100644
--- a/indra/newview/llpanelplaces.cpp
+++ b/indra/newview/llpanelplaces.cpp
@@ -347,8 +347,6 @@ BOOL LLPanelPlaces::postBuild()
 
 void LLPanelPlaces::onOpen(const LLSD& key)
 {
-	LLFirstUse::notUsingDestinationGuide(false);
-
 	if (!mPlaceProfile || !mLandmarkInfo)
 		return;
 
diff --git a/indra/newview/llpopupview.cpp b/indra/newview/llpopupview.cpp
index 18035c42f4..9fbb67a63a 100644
--- a/indra/newview/llpopupview.cpp
+++ b/indra/newview/llpopupview.cpp
@@ -138,64 +138,102 @@ BOOL LLPopupView::handleMouseEvent(boost::function<BOOL(LLView*, S32, S32)> func
 
 BOOL LLPopupView::handleMouseDown(S32 x, S32 y, MASK mask)
 {
-	if (!handleMouseEvent(boost::bind(&LLMouseHandler::handleMouseDown, _1, _2, _3, mask), view_visible_and_enabled, x, y, true))
+	BOOL handled = handleMouseEvent(boost::bind(&LLMouseHandler::handleMouseDown, _1, _2, _3, mask), view_visible_and_enabled, x, y, true);
+	if (!handled)
 	{
-		return FALSE;
+		handled = LLPanel::handleMouseDown(x, y, mask);
 	}
-	return TRUE;
+	return handled;
 }
 
 BOOL LLPopupView::handleMouseUp(S32 x, S32 y, MASK mask)
 {
-	return handleMouseEvent(boost::bind(&LLMouseHandler::handleMouseUp, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+	BOOL handled = handleMouseEvent(boost::bind(&LLMouseHandler::handleMouseUp, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+	if (!handled)
+	{
+		handled = LLPanel::handleMouseUp(x, y, mask);
+	}
+	return handled;
 }
 
 BOOL LLPopupView::handleMiddleMouseDown(S32 x, S32 y, MASK mask)
 {
-	if (!handleMouseEvent(boost::bind(&LLMouseHandler::handleMiddleMouseDown, _1, _2, _3, mask), view_visible_and_enabled, x, y, true))
+	BOOL handled = handleMouseEvent(boost::bind(&LLMouseHandler::handleMiddleMouseDown, _1, _2, _3, mask), view_visible_and_enabled, x, y, true);
+	if (!handled)
 	{
-		return FALSE;
+		handled = LLPanel::handleMiddleMouseDown(x, y, mask);
 	}
-	return TRUE;
+	return handled;	
 }
 
 BOOL LLPopupView::handleMiddleMouseUp(S32 x, S32 y, MASK mask)
 {
-	return handleMouseEvent(boost::bind(&LLMouseHandler::handleMiddleMouseUp, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+	BOOL handled = handleMouseEvent(boost::bind(&LLMouseHandler::handleMiddleMouseUp, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+	if (!handled)
+	{
+		handled = LLPanel::handleMiddleMouseUp(x, y, mask);
+	}
+	return handled;	
 }
 
 BOOL LLPopupView::handleRightMouseDown(S32 x, S32 y, MASK mask)
 {
-	if (!handleMouseEvent(boost::bind(&LLMouseHandler::handleRightMouseDown, _1, _2, _3, mask), view_visible_and_enabled, x, y, true))
+	BOOL handled = handleMouseEvent(boost::bind(&LLMouseHandler::handleRightMouseDown, _1, _2, _3, mask), view_visible_and_enabled, x, y, true);
+	if (!handled)
 	{
-		return FALSE;
+		handled = LLPanel::handleRightMouseDown(x, y, mask);
 	}
-	return TRUE;
+	return handled;	
 }
 
 BOOL LLPopupView::handleRightMouseUp(S32 x, S32 y, MASK mask)
 {
-	return handleMouseEvent(boost::bind(&LLMouseHandler::handleRightMouseUp, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+	BOOL handled = handleMouseEvent(boost::bind(&LLMouseHandler::handleRightMouseUp, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+	if (!handled)
+	{
+		handled = LLPanel::handleRightMouseUp(x, y, mask);
+	}
+	return handled;	
 }
 
 BOOL LLPopupView::handleDoubleClick(S32 x, S32 y, MASK mask)
 {
-	return handleMouseEvent(boost::bind(&LLMouseHandler::handleDoubleClick, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+	BOOL handled = handleMouseEvent(boost::bind(&LLMouseHandler::handleDoubleClick, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+	if (!handled)
+	{
+		handled = LLPanel::handleDoubleClick(x, y, mask);
+	}
+	return handled;	
 }
 
 BOOL LLPopupView::handleHover(S32 x, S32 y, MASK mask)
 {
-	return handleMouseEvent(boost::bind(&LLMouseHandler::handleHover, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+	BOOL handled = handleMouseEvent(boost::bind(&LLMouseHandler::handleHover, _1, _2, _3, mask), view_visible_and_enabled, x, y, false);
+	if (!handled)
+	{
+		handled = LLPanel::handleHover(x, y, mask);
+	}
+	return handled;	
 }
 
 BOOL LLPopupView::handleScrollWheel(S32 x, S32 y, S32 clicks)
 {
-	return handleMouseEvent(boost::bind(&LLMouseHandler::handleScrollWheel, _1, _2, _3, clicks), view_visible_and_enabled, x, y, false);
+	BOOL handled = handleMouseEvent(boost::bind(&LLMouseHandler::handleScrollWheel, _1, _2, _3, clicks), view_visible_and_enabled, x, y, false);
+	if (!handled)
+	{
+		handled = LLPanel::handleScrollWheel(x, y, clicks);
+	}
+	return handled;	
 }
 
 BOOL LLPopupView::handleToolTip(S32 x, S32 y, MASK mask)
 {
-	return handleMouseEvent(boost::bind(&LLMouseHandler::handleToolTip, _1, _2, _3, mask), view_visible, x, y, false);
+	BOOL handled = handleMouseEvent(boost::bind(&LLMouseHandler::handleToolTip, _1, _2, _3, mask), view_visible, x, y, false);
+	if (!handled)
+	{
+		handled = LLPanel::handleToolTip(x, y, mask);
+	}
+	return handled;
 }
 
 void LLPopupView::addPopup(LLView* popup)
diff --git a/indra/newview/llrootview.h b/indra/newview/llrootview.h
index 4b1ba15a0b..5223a314f3 100644
--- a/indra/newview/llrootview.h
+++ b/indra/newview/llrootview.h
@@ -42,27 +42,5 @@ public:
 	LLRootView(const Params& p)
 	:	LLView(p)
 	{}
-
-	// added to provide possibility to handle mouse click event inside all application
-	// window without creating any floater
-	typedef boost::signals2::signal<void(S32 x, S32 y, MASK mask)>
-			mouse_signal_t;
-
-	private:
-		mouse_signal_t mMouseDownSignal;
-
-	public:
-	/*virtual*/
-	BOOL handleMouseDown(S32 x, S32 y, MASK mask)
-	{
-		mMouseDownSignal(x, y, mask);
-		return LLView::handleMouseDown(x, y, mask);
-	}
-
-	boost::signals2::connection addMouseDownCallback(
-			const mouse_signal_t::slot_type& cb)
-	{
-		return mMouseDownSignal.connect(cb);
-	}
 };
 #endif //LL_LLROOTVIEW_H
diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp
index 53d8a5c19e..9cb6df6c30 100644
--- a/indra/newview/llsidetray.cpp
+++ b/indra/newview/llsidetray.cpp
@@ -878,7 +878,6 @@ void	LLSideTray::createButtons	()
 		}
 	}
 	LLHints::registerHintTarget("inventory_btn", mTabButtons["sidebar_inventory"]->getHandle());
-	LLHints::registerHintTarget("dest_guide_btn", mTabButtons["sidebar_places"]->getHandle());
 }
 
 void		LLSideTray::processTriState ()
diff --git a/indra/newview/lltransientfloatermgr.cpp b/indra/newview/lltransientfloatermgr.cpp
index 78dd602f39..01e41925c9 100644
--- a/indra/newview/lltransientfloatermgr.cpp
+++ b/indra/newview/lltransientfloatermgr.cpp
@@ -36,8 +36,8 @@
 
 LLTransientFloaterMgr::LLTransientFloaterMgr()
 {
-	gViewerWindow->getRootView()->addMouseDownCallback(boost::bind(
-			&LLTransientFloaterMgr::leftMouseClickCallback, this, _1, _2, _3));
+	gViewerWindow->getRootView()->getChild<LLUICtrl>("popup_holder")->setMouseDownCallback(boost::bind(
+			&LLTransientFloaterMgr::leftMouseClickCallback, this, _2, _3, _4));
 
 	mGroupControls.insert(std::pair<ETransientGroup, std::set<LLView*> >(GLOBAL, std::set<LLView*>()));
 	mGroupControls.insert(std::pair<ETransientGroup, std::set<LLView*> >(DOCKED, std::set<LLView*>()));
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 0ff5181cc5..0454d4a249 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -44,7 +44,7 @@
 #include "llconsole.h"
 #include "lldebugview.h"
 #include "llfilepicker.h"
-//#include "llfirstuse.h"
+#include "llfirstuse.h"
 #include "llfloaterbuy.h"
 #include "llfloaterbuycontents.h"
 #include "llbuycurrencyhtml.h"
@@ -855,6 +855,7 @@ void LLDestinationGuideToggle()
 		}
 		else
 		{
+			LLFirstUse::notUsingDestinationGuide(false);
 			destination_guide->setVisible( true );
 		}
 	}
diff --git a/indra/newview/skins/default/textures/arrow_keys.png b/indra/newview/skins/default/textures/arrow_keys.png
new file mode 100644
index 0000000000..f19af59251
Binary files /dev/null and b/indra/newview/skins/default/textures/arrow_keys.png differ
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index cf5a6ad255..6db1ae9bc0 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -6463,6 +6463,22 @@ Mute everyone?
     To walk or run, open the Move Panel and use the directional arrows to navigate. You can also use the directional keys on your keyboard.
   </notification>
 
+  <notification
+  name="HintMoveArrows"
+  label="Move"
+  type="hint"
+  unique="true">
+    To walk, use the directional keys on your keyboard. You can run by pressing the Up arrow twice.
+  </notification>
+  
+  <notification
+  name="HintView"
+  label="View"
+  type="hint"
+  unique="true">
+    To change your camera view, use the Orbit and Pan controls below. Reset your view by pressing Escape or walking.
+  </notification>
+
   <notification
   name="HintInventory"
   label="Inventory"
diff --git a/indra/newview/skins/default/xui/en/panel_hint_image.xml b/indra/newview/skins/default/xui/en/panel_hint_image.xml
new file mode 100644
index 0000000000..31a310c07b
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_hint_image.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ width="205"
+ height="200"
+ layout="topleft">
+  <text name="hint_title"
+        font="SansSerifMedium" 
+        left="8"
+        right="180"
+        top="8"
+        bottom="20"
+        follows="left|right|top"
+        text_color="Black"
+        wrap="false"/>
+  <icon name="hint_image"
+        left="42"
+        top="25"
+        width="115"
+        height="86"
+        image_name="arrow_keys.png"
+        />
+  <text name="hint_text"
+        left="8"
+        right="197"
+        top_pad="5"
+        bottom="92"
+        follows="all" 
+        text_color="Black"
+        wrap="true"/>
+  <button right="197" 
+          top="8"
+          width="16" 
+          height="16"
+          name="close" 
+          follows="right|top" 
+          image_color="DkGray" 
+          image_unselected="Icon_Close_Foreground"
+          image_selected="Icon_Close_Press"/>
+</panel>
-- 
cgit v1.2.3


From dd2eff8da2b2508d5fc46492147e015d2455f957 Mon Sep 17 00:00:00 2001
From: callum <none@none>
Date: Thu, 7 Oct 2010 12:08:03 -0700
Subject: EXP-167: Quit On Login Page Activated - viewer code /default setting

---
 indra/newview/app_settings/settings.xml | 11 +++++++++++
 indra/newview/llappviewer.cpp           |  8 ++++++++
 indra/newview/llappviewer.h             |  1 +
 indra/newview/llstartup.cpp             | 10 +++++++++-
 4 files changed, 29 insertions(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index d5cfc11c2c..142378b540 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -6535,6 +6535,17 @@
       <key>Value</key>
       <real>0.0</real>
     </map>
+    <key>QuitOnLoginActivated</key>
+    <map>
+      <key>Comment</key>
+      <string>Quit if login page is activated (used when auto login is on and users must not be able to login manually)</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>RadioLandBrushAction</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index a9bdabe794..e6661e4c9a 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2951,6 +2951,14 @@ void LLAppViewer::earlyExit(const std::string& name, const LLSD& substitutions)
 	LLNotificationsUtil::add(name, substitutions, LLSD(), finish_early_exit);
 }
 
+// case where we need the viewer to exit without any need for notifications
+void LLAppViewer::earlyExitNoNotify()
+{
+   	llwarns << "app_early_exit with no notification: " << llendl;
+	gDoDisconnect = TRUE;
+	finish_early_exit( LLSD(), LLSD() );
+}
+
 void LLAppViewer::forceExit(S32 arg)
 {
     removeMarkerFile();
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 56d88f07c8..b0f8c1dc3d 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -70,6 +70,7 @@ public:
 	void userQuit(); // The users asks to quit. Confirm, then requestQuit()
     void earlyExit(const std::string& name, 
 				   const LLSD& substitutions = LLSD()); // Display an error dialog and forcibly quit.
+	void LLAppViewer::earlyExitNoNotify(); // Do not display error dialog then forcibly quit.
     void forceExit(S32 arg); // exit() immediately (after some cleanup).
     void abortQuit();  // Called to abort a quit request.
 
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index c56cacd12b..1a42500ec4 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -706,7 +706,15 @@ bool idle_startup()
 	if (STATE_LOGIN_SHOW == LLStartUp::getStartupState())
 	{
 		LL_DEBUGS("AppInit") << "Initializing Window" << LL_ENDL;
-		
+
+		// if auto login is on and setting to quit if the login page is activated
+		// is enabled, then go ahead and exit
+		if ( gSavedSettings.getBOOL("AutoLogin") && gSavedSettings.getBOOL("QuitOnLoginActivated") )
+		{
+			// no requirement for notification here - just exit
+			LLAppViewer::instance()->earlyExitNoNotify();
+		}
+
 		gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW);
 
 		timeout_count = 0;
-- 
cgit v1.2.3


From c154e4b794489ff876b60b9ccfcb72ec1836cea2 Mon Sep 17 00:00:00 2001
From: Monroe Linden <monroe@lindenlab.com>
Date: Thu, 7 Oct 2010 14:07:31 -0700
Subject: Made VoiceCallsRejectAll apply to group voice invites as well as p2p
 and ad-hoc invites.

Fixed some code in LLIMMgr that had the incoming call dialog confused with a notification.

Reviewed by Richard.
---
 indra/newview/llimview.cpp | 40 ++++++++++++++++++++++------------------
 indra/newview/llimview.h   |  2 +-
 2 files changed, 23 insertions(+), 19 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 6b4e1f7289..87a43a48dd 100644
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -1990,7 +1990,7 @@ void LLIncomingCallDialog::onOpen(const LLSD& key)
 void LLIncomingCallDialog::onAccept(void* user_data)
 {
 	LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data;
-	self->processCallResponse(0);
+	processCallResponse(0, self->mPayload);
 	self->closeFloater();
 }
 
@@ -1998,7 +1998,7 @@ void LLIncomingCallDialog::onAccept(void* user_data)
 void LLIncomingCallDialog::onReject(void* user_data)
 {
 	LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data;
-	self->processCallResponse(1);
+	processCallResponse(1, self->mPayload);
 	self->closeFloater();
 }
 
@@ -2006,20 +2006,21 @@ void LLIncomingCallDialog::onReject(void* user_data)
 void LLIncomingCallDialog::onStartIM(void* user_data)
 {
 	LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data;
-	self->processCallResponse(2);
+	processCallResponse(2, self->mPayload);
 	self->closeFloater();
 }
 
-void LLIncomingCallDialog::processCallResponse(S32 response)
+// static
+void LLIncomingCallDialog::processCallResponse(S32 response, const LLSD &payload)
 {
 	if (!gIMMgr || gDisconnected)
 		return;
 
-	LLUUID session_id = mPayload["session_id"].asUUID();
-	LLUUID caller_id = mPayload["caller_id"].asUUID();
-	std::string session_name = mPayload["session_name"].asString();
-	EInstantMessage type = (EInstantMessage)mPayload["type"].asInteger();
-	LLIMMgr::EInvitationType inv_type = (LLIMMgr::EInvitationType)mPayload["inv_type"].asInteger();
+	LLUUID session_id = payload["session_id"].asUUID();
+	LLUUID caller_id = payload["caller_id"].asUUID();
+	std::string session_name = payload["session_name"].asString();
+	EInstantMessage type = (EInstantMessage)payload["type"].asInteger();
+	LLIMMgr::EInvitationType inv_type = (LLIMMgr::EInvitationType)payload["inv_type"].asInteger();
 	bool voice = true;
 	switch(response)
 	{
@@ -2036,8 +2037,8 @@ void LLIncomingCallDialog::processCallResponse(S32 response)
 			session_id = gIMMgr->addP2PSession(
 				session_name,
 				caller_id,
-				mPayload["session_handle"].asString(),
-				mPayload["session_uri"].asString());
+				payload["session_handle"].asString(),
+				payload["session_uri"].asString());
 
 			if (voice)
 			{
@@ -2098,10 +2099,10 @@ void LLIncomingCallDialog::processCallResponse(S32 response)
 						inv_type));
 
 				// send notification message to the corresponding chat 
-				if (mPayload["notify_box_type"].asString() == "VoiceInviteGroup" || mPayload["notify_box_type"].asString() == "VoiceInviteAdHoc")
+				if (payload["notify_box_type"].asString() == "VoiceInviteGroup" || payload["notify_box_type"].asString() == "VoiceInviteAdHoc")
 				{
 					LLStringUtil::format_map_t string_args;
-					string_args["[NAME]"] = mPayload["caller_name"].asString();
+					string_args["[NAME]"] = payload["caller_name"].asString();
 					std::string message = LLTrans::getString("name_started_call", string_args);
 					LLIMModel::getInstance()->addMessageSilently(session_id, SYSTEM_FROM, LLUUID::null, message);
 				}
@@ -2118,7 +2119,7 @@ void LLIncomingCallDialog::processCallResponse(S32 response)
 		{
 			if(LLVoiceClient::getInstance())
 			{
-				std::string s = mPayload["session_handle"].asString();
+				std::string s = payload["session_handle"].asString();
 				LLVoiceClient::getInstance()->declineInvite(s);
 			}
 		}
@@ -2525,16 +2526,19 @@ void LLIMMgr::inviteToSession(
 	std::string question_type = "VoiceInviteQuestionDefault";
 
 	BOOL ad_hoc_invite = FALSE;
+	BOOL voice_invite = FALSE;
 	if(type == IM_SESSION_P2P_INVITE)
 	{
 		//P2P is different...they only have voice invitations
 		notify_box_type = "VoiceInviteP2P";
+		voice_invite = TRUE;
 	}
 	else if ( gAgent.isInGroup(session_id) )
 	{
 		//only really old school groups have voice invitations
 		notify_box_type = "VoiceInviteGroup";
 		question_type = "VoiceInviteQuestionGroup";
+		voice_invite = TRUE;
 	}
 	else if ( inv_type == INVITATION_TYPE_VOICE )
 	{
@@ -2542,6 +2546,7 @@ void LLIMMgr::inviteToSession(
 		//and a voice ad-hoc
 		notify_box_type = "VoiceInviteAdHoc";
 		ad_hoc_invite = TRUE;
+		voice_invite = TRUE;
 	}
 	else if ( inv_type == INVITATION_TYPE_IMMEDIATE )
 	{
@@ -2565,13 +2570,12 @@ void LLIMMgr::inviteToSession(
 	if (channelp && channelp->callStarted())
 	{
 		// you have already started a call to the other user, so just accept the invite
-		LLNotifications::instance().forceResponse(LLNotification::Params("VoiceInviteP2P").payload(payload), 0);
+		LLIncomingCallDialog::processCallResponse(0, payload);
 		return;
 	}
 
-	if (type == IM_SESSION_P2P_INVITE || ad_hoc_invite)
+	if (voice_invite)
 	{
-			
 		if	(	// if we're rejecting all incoming call requests
 				gSavedSettings.getBOOL("VoiceCallsRejectAll")	
 				// or we're rejecting non-friend voice calls and this isn't a friend	
@@ -2579,7 +2583,7 @@ void LLIMMgr::inviteToSession(
 			)
 		{
 			// silently decline the call
-			LLNotifications::instance().forceResponse(LLNotification::Params("VoiceInviteP2P").payload(payload), 1);
+			LLIncomingCallDialog::processCallResponse(1, payload);
 			return;
 		}
 	}
diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h
index f7a4406f00..352936347d 100644
--- a/indra/newview/llimview.h
+++ b/indra/newview/llimview.h
@@ -538,9 +538,9 @@ public:
 	static void onReject(void* user_data);
 	static void onStartIM(void* user_data);
 
+	static void processCallResponse(S32 response, const LLSD& payload);
 private:
 	/*virtual*/ void onLifetimeExpired();
-	void processCallResponse(S32 response);
 };
 
 class LLOutgoingCallDialog : public LLCallDialog
-- 
cgit v1.2.3


From 49392504d95abbb2518479baa969c2963bd73adf Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Thu, 7 Oct 2010 15:01:07 -0700
Subject: enabled alternate move hint in skylight skin only

---
 indra/newview/llfirstuse.cpp                                   | 3 ++-
 indra/newview/skins/default/xui/en/notification_visibility.xml | 1 +
 indra/newview/skins/default/xui/en/panel_hint_image.xml        | 4 ++--
 3 files changed, 5 insertions(+), 3 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llfirstuse.cpp b/indra/newview/llfirstuse.cpp
index 4d6302596b..b757f25d5e 100644
--- a/indra/newview/llfirstuse.cpp
+++ b/indra/newview/llfirstuse.cpp
@@ -113,7 +113,8 @@ void LLFirstUse::notUsingSidePanel(bool enable)
 // static
 void LLFirstUse::notMoving(bool enable)
 {
-	//firstUseNotification("FirstNotMoving", enable, "HintMove", LLSD(), LLSD().with("target", "move_btn").with("direction", "top"));
+	// fire off 2 notifications and rely on filtering to select the relevant one
+	firstUseNotification("FirstNotMoving", enable, "HintMove", LLSD(), LLSD().with("target", "move_btn").with("direction", "top"));
 	firstUseNotification("FirstNotMoving", enable, "HintMoveArrows", LLSD(), LLSD().with("hint_image", "arrow_keys.png"));
 }
 
diff --git a/indra/newview/skins/default/xui/en/notification_visibility.xml b/indra/newview/skins/default/xui/en/notification_visibility.xml
index ea32a83b83..d32066a5a5 100644
--- a/indra/newview/skins/default/xui/en/notification_visibility.xml
+++ b/indra/newview/skins/default/xui/en/notification_visibility.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" ?>
 <notification_visibility>
+  <hide name="HintMoveArrows"/>
 	<show/> 
 </notification_visibility>
 
diff --git a/indra/newview/skins/default/xui/en/panel_hint_image.xml b/indra/newview/skins/default/xui/en/panel_hint_image.xml
index 31a310c07b..00b6e42497 100644
--- a/indra/newview/skins/default/xui/en/panel_hint_image.xml
+++ b/indra/newview/skins/default/xui/en/panel_hint_image.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 <panel
  width="205"
- height="200"
+ height="140"
  layout="topleft">
   <text name="hint_title"
         font="SansSerifMedium" 
@@ -23,7 +23,7 @@
         left="8"
         right="197"
         top_pad="5"
-        bottom="92"
+        bottom="120"
         follows="all" 
         text_color="Black"
         wrap="true"/>
-- 
cgit v1.2.3


From 2292360d8a001e05c8b95a1dc3db1c00dfec94f5 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Thu, 7 Oct 2010 15:26:33 -0700
Subject: removed word "below" from View Hint

---
 indra/newview/skins/default/xui/en/notifications.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 6db1ae9bc0..834fe6f966 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -6476,7 +6476,7 @@ Mute everyone?
   label="View"
   type="hint"
   unique="true">
-    To change your camera view, use the Orbit and Pan controls below. Reset your view by pressing Escape or walking.
+    To change your camera view, use the Orbit and Pan controls. Reset your view by pressing Escape or walking.
   </notification>
 
   <notification
-- 
cgit v1.2.3


From d8e40a49ed6b57c5f2b0325803a11cf04b987652 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Thu, 7 Oct 2010 15:35:17 -0700
Subject: EXP-156 FIXED  custom Skylight hints moved move hint down to bottom
 of screen made destination hint go away on teleport

---
 indra/newview/llbottomtray.cpp    | 1 +
 indra/newview/llfirstuse.cpp      | 2 +-
 indra/newview/llviewermessage.cpp | 2 ++
 3 files changed, 4 insertions(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp
index d869850b7c..fd11045f56 100644
--- a/indra/newview/llbottomtray.cpp
+++ b/indra/newview/llbottomtray.cpp
@@ -517,6 +517,7 @@ void LLBottomTray::toggleCameraControls()
 
 BOOL LLBottomTray::postBuild()
 {
+	LLHints::registerHintTarget("bottom_tray", LLView::getHandle());
 	LLHints::registerHintTarget("dest_guide_btn", getChild<LLUICtrl>("destinations_btn")->getHandle());
 
 	LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("NearbyChatBar.Action", boost::bind(&LLBottomTray::onContextMenuItemClicked, this, _2));
diff --git a/indra/newview/llfirstuse.cpp b/indra/newview/llfirstuse.cpp
index b757f25d5e..5d6197c688 100644
--- a/indra/newview/llfirstuse.cpp
+++ b/indra/newview/llfirstuse.cpp
@@ -115,7 +115,7 @@ void LLFirstUse::notMoving(bool enable)
 {
 	// fire off 2 notifications and rely on filtering to select the relevant one
 	firstUseNotification("FirstNotMoving", enable, "HintMove", LLSD(), LLSD().with("target", "move_btn").with("direction", "top"));
-	firstUseNotification("FirstNotMoving", enable, "HintMoveArrows", LLSD(), LLSD().with("hint_image", "arrow_keys.png"));
+	firstUseNotification("FirstNotMoving", enable, "HintMoveArrows", LLSD(), LLSD().with("target", "bottom_tray").with("direction", "top").with("hint_image", "arrow_keys.png").with("down_arrow", ""));
 }
 
 // static
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 26b7e0fb6d..79a3bc5776 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -3201,6 +3201,8 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)
 // 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);
 
-- 
cgit v1.2.3


From bd4afcfba29a763d2253b59a86ec48228a1c6fa8 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Fri, 8 Oct 2010 14:27:42 -0700
Subject: EXP-137 FIXED Nametag text and borders do not align in Skylight
 Viewer fix for prim media and hud text incorrect positioning when destination
 guide is open

---
 indra/newview/llpanelprimmediacontrols.cpp |  8 ++++----
 indra/newview/llviewerwindow.cpp           | 13 ++-----------
 2 files changed, 6 insertions(+), 15 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp
index b04971f980..de2428feed 100644
--- a/indra/newview/llpanelprimmediacontrols.cpp
+++ b/indra/newview/llpanelprimmediacontrols.cpp
@@ -620,12 +620,12 @@ void LLPanelPrimMediaControls::updateShape()
 		// convert screenspace bbox to pixels (in screen coords)
 		LLRect window_rect = gViewerWindow->getWorldViewRectScaled();
 		LLCoordGL screen_min;
-		screen_min.mX = llround((F32)window_rect.getWidth() * (min.mV[VX] + 1.f) * 0.5f);
-		screen_min.mY = llround((F32)window_rect.getHeight() * (min.mV[VY] + 1.f) * 0.5f);
+		screen_min.mX = llround((F32)window_rect.mLeft + (F32)window_rect.getWidth() * (min.mV[VX] + 1.f) * 0.5f);
+		screen_min.mY = llround((F32)window_rect.mBottom + (F32)window_rect.getHeight() * (min.mV[VY] + 1.f) * 0.5f);
 		
 		LLCoordGL screen_max;
-		screen_max.mX = llround((F32)window_rect.getWidth() * (max.mV[VX] + 1.f) * 0.5f);
-		screen_max.mY = llround((F32)window_rect.getHeight() * (max.mV[VY] + 1.f) * 0.5f);
+		screen_max.mX = llround((F32)window_rect.mLeft + (F32)window_rect.getWidth() * (max.mV[VX] + 1.f) * 0.5f);
+		screen_max.mY = llround((F32)window_rect.mBottom + (F32)window_rect.getHeight() * (max.mV[VY] + 1.f) * 0.5f);
 		
 		// grow panel so that screenspace bounding box fits inside "media_region" element of panel
 		LLRect media_panel_rect;
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index c6ed3f8979..b49d342126 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -4262,17 +4262,8 @@ void LLViewerWindow::setup3DRender()
 
 void LLViewerWindow::setup3DViewport(S32 x_offset, S32 y_offset)
 {
-	if (LLRenderTarget::getCurrentBoundTarget() != NULL)
-	{
-		// don't use translation component of mWorldViewRectRaw, as we are already in a properly sized render target
-		gGLViewport[0] = x_offset;
-		gGLViewport[1] = y_offset;
-	}
-	else
-	{
-		gGLViewport[0] = mWorldViewRectRaw.mLeft + x_offset;
-		gGLViewport[1] = mWorldViewRectRaw.mBottom + 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]);
-- 
cgit v1.2.3


From 688c2a73cdf982a4fe5ee0bfea0a52135fc461ef Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Fri, 8 Oct 2010 15:56:34 -0700
Subject: made progressbar derive from lluictrl and take percentage as llsd
 value

---
 indra/newview/llpanelprimmediacontrols.cpp | 2 +-
 indra/newview/llprogressview.cpp           | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp
index de2428feed..614700fb0a 100644
--- a/indra/newview/llpanelprimmediacontrols.cpp
+++ b/indra/newview/llpanelprimmediacontrols.cpp
@@ -519,7 +519,7 @@ void LLPanelPrimMediaControls::updateShape()
 			if(LLPluginClassMediaOwner::MEDIA_LOADING == media_plugin->getStatus())
 			{	
 				mMediaProgressPanel->setVisible(true);
-				mMediaProgressBar->setPercent(media_plugin->getProgressPercent());
+				mMediaProgressBar->setValue(media_plugin->getProgressPercent());
 			}
 			else
 			{
diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp
index e9504cbba0..db02d76139 100644
--- a/indra/newview/llprogressview.cpp
+++ b/indra/newview/llprogressview.cpp
@@ -207,7 +207,7 @@ void LLProgressView::setText(const std::string& text)
 
 void LLProgressView::setPercent(const F32 percent)
 {
-	mProgressBar->setPercent(percent);
+	mProgressBar->setValue(percent);
 }
 
 void LLProgressView::setMessage(const std::string& msg)
-- 
cgit v1.2.3


From 78f0e65d63950dab8e72be6db0df22064271cfa2 Mon Sep 17 00:00:00 2001
From: callum <none@none>
Date: Fri, 8 Oct 2010 16:18:47 -0700
Subject: EXP-170 Able to buy objects in Skylight viewer (viewer code and
 default settings changes) Note: this also adds a setting to turn off 'Pay'
 too.

---
 indra/newview/app_settings/settings.xml | 22 ++++++++++
 indra/newview/lltoolpie.cpp             | 73 ++++++++++++++++++++++-----------
 indra/newview/lltoolpie.h               |  5 ++-
 3 files changed, 73 insertions(+), 27 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 142378b540..f9d930a13a 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -2699,6 +2699,28 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
+    <key>ClickActionBuyEnabled</key>
+    <map>
+      <key>Comment</key>
+      <string>Enable click to buy actions in tool pie menu</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
+    <key>ClickActionPayEnabled</key>
+    <map>
+      <key>Comment</key>
+      <string>Enable click to pay actions in tool pie menu</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
     <key>DoubleClickAutoPilot</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index 2ee3e4ffed..583d3c707b 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -80,9 +80,11 @@ LLToolPie::LLToolPie()
 :	LLTool(std::string("Pie")),
 	mGrabMouseButtonDown( FALSE ),
 	mMouseOutsideSlop( FALSE ),
-	mClickAction(0)
-{ }
-
+	mClickAction(0),
+	mClickActionBuyEnabled( gSavedSettings.getBOOL("ClickActionBuyEnabled") ),
+	mClickActionPayEnabled( gSavedSettings.getBOOL("ClickActionPayEnabled") )
+{
+}
 
 BOOL LLToolPie::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down)
 {
@@ -210,12 +212,28 @@ BOOL LLToolPie::pickLeftMouseDownCallback()
 				} // else nothing (fall through to touch)
 			}
 		case CLICK_ACTION_PAY:
-			if ((object && object->flagTakesMoney())
-				|| (parent && parent->flagTakesMoney()))
+			if ( mClickActionPayEnabled )
+			{
+				if ((object && object->flagTakesMoney())
+					|| (parent && parent->flagTakesMoney()))
+				{
+					// pay event goes to object actually clicked on
+					mClickActionObject = object;
+					mLeftClickSelection = LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE);
+					if (LLSelectMgr::getInstance()->selectGetAllValid())
+					{
+						// call this right away, since we have all the info we need to continue the action
+						selectionPropertiesReceived();
+					}
+					return TRUE;
+				}
+			}
+			break;
+		case CLICK_ACTION_BUY:
+			if ( mClickActionBuyEnabled )
 			{
-				// pay event goes to object actually clicked on
-				mClickActionObject = object;
-				mLeftClickSelection = LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE);
+				mClickActionObject = parent;
+				mLeftClickSelection = LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE, TRUE);
 				if (LLSelectMgr::getInstance()->selectGetAllValid())
 				{
 					// call this right away, since we have all the info we need to continue the action
@@ -224,15 +242,6 @@ BOOL LLToolPie::pickLeftMouseDownCallback()
 				return TRUE;
 			}
 			break;
-		case CLICK_ACTION_BUY:
-			mClickActionObject = parent;
-			mLeftClickSelection = LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE, TRUE);
-			if (LLSelectMgr::getInstance()->selectGetAllValid())
-			{
-				// call this right away, since we have all the info we need to continue the action
-				selectionPropertiesReceived();
-			}
-			return TRUE;
 		case CLICK_ACTION_OPEN:
 			if (parent && parent->allowOpen())
 			{
@@ -392,7 +401,7 @@ U8 final_click_action(LLViewerObject* obj)
 	return click_action;
 }
 
-ECursorType cursor_from_object(LLViewerObject* object)
+ECursorType LLToolPie::cursorFromObject(LLViewerObject* object)
 {
 	LLViewerObject* parent = NULL;
 	if (object)
@@ -412,7 +421,10 @@ ECursorType cursor_from_object(LLViewerObject* object)
 		}
 		break;
 	case CLICK_ACTION_BUY:
-		cursor = UI_CURSOR_TOOLBUY;
+		if ( mClickActionBuyEnabled )
+		{
+			cursor = UI_CURSOR_TOOLBUY;
+		}
 		break;
 	case CLICK_ACTION_OPEN:
 		// Open always opens the parent.
@@ -422,10 +434,13 @@ ECursorType cursor_from_object(LLViewerObject* object)
 		}
 		break;
 	case CLICK_ACTION_PAY:	
-		if ((object && object->flagTakesMoney())
-			|| (parent && parent->flagTakesMoney()))
+		if ( mClickActionPayEnabled )
 		{
-			cursor = UI_CURSOR_TOOLBUY;
+			if ((object && object->flagTakesMoney())
+				|| (parent && parent->flagTakesMoney()))
+			{
+				cursor = UI_CURSOR_TOOLBUY;
+			}
 		}
 		break;
 	case CLICK_ACTION_ZOOM:
@@ -473,10 +488,16 @@ void LLToolPie::selectionPropertiesReceived()
 			switch (click_action)
 			{
 			case CLICK_ACTION_BUY:
-				handle_buy();
+				if ( LLToolPie::getInstance()->mClickActionBuyEnabled )
+				{
+					handle_buy();
+				}
 				break;
 			case CLICK_ACTION_PAY:
-				handle_give_money_dialog();
+				if ( LLToolPie::getInstance()->mClickActionPayEnabled )
+				{
+					handle_give_money_dialog();
+				}
 				break;
 			case CLICK_ACTION_OPEN:
 				LLFloaterReg::showInstance("openobject");
@@ -517,7 +538,7 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
 	else if (click_action_object && useClickAction(mask, click_action_object, click_action_object->getRootEdit()))
 	{
 		show_highlight = true;
-		ECursorType cursor = cursor_from_object(click_action_object);
+		ECursorType cursor = cursorFromObject(click_action_object);
 		gViewerWindow->setCursor(cursor);
 		lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl;
 	}
@@ -570,7 +591,9 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask)
 	{
 		switch(click_action)
 		{
+			// NOTE: mClickActionBuyEnabled flag enables/disables BUY action but setting cursor to default is okay
 		case CLICK_ACTION_BUY:
+			// NOTE: mClickActionPayEnabled flag enables/disables PAY action but setting cursor to default is okay
 		case CLICK_ACTION_PAY:
 		case CLICK_ACTION_OPEN:
 		case CLICK_ACTION_ZOOM:
diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h
index 65cb3e36a7..77200a1da4 100644
--- a/indra/newview/lltoolpie.h
+++ b/indra/newview/lltoolpie.h
@@ -80,6 +80,7 @@ private:
 	BOOL useClickAction		(MASK mask, LLViewerObject* object,LLViewerObject* parent);
 	
 	void showVisualContextMenuEffect();
+	ECursorType cursorFromObject(LLViewerObject* object);
 
 	bool handleMediaClick(const LLPickInfo& info);
 	bool handleMediaHover(const LLPickInfo& info);
@@ -96,8 +97,8 @@ private:
 	LLPointer<LLViewerObject> mClickActionObject;
 	U8					mClickAction;
 	LLSafeHandle<LLObjectSelection> mLeftClickSelection;
-
+	BOOL				mClickActionBuyEnabled;
+	BOOL				mClickActionPayEnabled;
 };
 
-
 #endif
-- 
cgit v1.2.3


From f65bd3c1f18675910c9d49db217a1926bd04494e Mon Sep 17 00:00:00 2001
From: callum <none@none>
Date: Fri, 8 Oct 2010 16:41:33 -0700
Subject: Fix for Reopened EXP-167 Add option to quit instead of going back to
 login screen.

---
 indra/newview/llstartup.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 1a42500ec4..d9234425b8 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -709,7 +709,7 @@ bool idle_startup()
 
 		// if auto login is on and setting to quit if the login page is activated
 		// is enabled, then go ahead and exit
-		if ( gSavedSettings.getBOOL("AutoLogin") && gSavedSettings.getBOOL("QuitOnLoginActivated") )
+		if ( show_connect_box && gSavedSettings.getBOOL("AutoLogin") && gSavedSettings.getBOOL("QuitOnLoginActivated") )
 		{
 			// no requirement for notification here - just exit
 			LLAppViewer::instance()->earlyExitNoNotify();
-- 
cgit v1.2.3


From 77d1fa974ad6cc9be0b84e574b455693bfa7f702 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Fri, 8 Oct 2010 17:37:38 -0700
Subject: added "FastQuit" option for forceful termination, default is off

---
 indra/newview/app_settings/settings.xml | 11 +++++++++++
 indra/newview/llappviewer.cpp           | 14 ++++++++++++++
 indra/newview/llappviewer.h             |  1 +
 indra/newview/llappviewerwin32.cpp      |  6 ++++++
 4 files changed, 32 insertions(+)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 142378b540..bc06078928 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -2962,6 +2962,17 @@
         <string>Boolean</string>
         <key>Value</key>
         <integer>0</integer>
+    </map>
+    <key>FastQuit</key>
+      <map>
+        <key>Comment</key>
+        <string>Quits as quickly as possible, only sending logout request before forcefully terminating.  Use with care, as this might result in data corruption or loss.</string>
+        <key>Persist</key>
+        <integer>1</integer>
+        <key>Type</key>
+        <string>Boolean</string>
+        <key>Value</key>
+        <integer>0</integer>
     </map>
 	<key>FeatureManagerHTTPTable</key>
       <map>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index e6661e4c9a..91fae709df 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2879,8 +2879,22 @@ void LLAppViewer::forceQuit()
 	LLApp::setQuitting(); 
 }
 
+void LLAppViewer::fastQuit()
+{
+	if (LLStartUp::getStartupState() >= STATE_STARTED)
+	{
+		sendLogoutRequest();
+	}
+	_exit(isError());	
+}
+
 void LLAppViewer::requestQuit()
 {
+	if (gSavedSettings.getBOOL("FastQuit"))
+	{
+		fastQuit();
+	}
+
 	llinfos << "requestQuit" << llendl;
 
 	LLViewerRegion* region = gAgent.getRegion();
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index b0f8c1dc3d..62ebd0712e 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -66,6 +66,7 @@ public:
 
 	// Application control
 	void forceQuit(); // Puts the viewer into 'shutting down without error' mode.
+	void fastQuit(); // Shuts down the viewer immediately after sending a logout message
 	void requestQuit(); // Request a quit. A kinder, gentler quit.
 	void userQuit(); // The users asks to quit. Confirm, then requestQuit()
     void earlyExit(const std::string& name, 
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index d328567a0e..2c6f014d17 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -175,6 +175,12 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,
 		viewer_app_ptr->mainLoop();
 	}
 
+	if (gSavedSettings.getBOOL("FastQuit"))
+	{
+		viewer_app_ptr->fastQuit();
+	}
+
+
 	if (!LLApp::isError())
 	{
 		//
-- 
cgit v1.2.3


From 67ac18dbe0e76a3b94f09768ee61b78585c0f2a0 Mon Sep 17 00:00:00 2001
From: Richard Nelson <none@none>
Date: Mon, 11 Oct 2010 12:27:51 -0700
Subject: fix for linux build

---
 indra/newview/llappviewer.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 62ebd0712e..0e7dbb738b 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -71,7 +71,7 @@ public:
 	void userQuit(); // The users asks to quit. Confirm, then requestQuit()
     void earlyExit(const std::string& name, 
 				   const LLSD& substitutions = LLSD()); // Display an error dialog and forcibly quit.
-	void LLAppViewer::earlyExitNoNotify(); // Do not display error dialog then forcibly quit.
+	void earlyExitNoNotify(); // Do not display error dialog then forcibly quit.
     void forceExit(S32 arg); // exit() immediately (after some cleanup).
     void abortQuit();  // Called to abort a quit request.
 
-- 
cgit v1.2.3


From 092e595b25e3e0cd27c480d864bfd894aaf3c987 Mon Sep 17 00:00:00 2001
From: Richard Nelson <none@none>
Date: Mon, 11 Oct 2010 12:31:00 -0700
Subject: EXP-172 FIXED Property lines flash on and off when right clicking on
 land in Skylight viewer

---
 indra/newview/app_settings/settings.xml | 11 +++++++++++
 indra/newview/llviewerparcelmgr.cpp     |  2 +-
 2 files changed, 12 insertions(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 1c7e391ccb..f3dea5b88b 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -8505,6 +8505,17 @@
       <key>Value</key>
       <integer>512</integer>
     </map>
+    <key>RenderParcelSelection</key>
+    <map>
+      <key>Comment</key>
+      <string>Display selected parcel outline</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
     <key>RotateRight</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp
index 660bb93562..3c9e351ca1 100644
--- a/indra/newview/llviewerparcelmgr.cpp
+++ b/indra/newview/llviewerparcelmgr.cpp
@@ -850,7 +850,7 @@ LLParcel* LLViewerParcelMgr::getCollisionParcel() const
 
 void LLViewerParcelMgr::render()
 {
-	if (mSelected && mRenderSelection)
+	if (mSelected && mRenderSelection && gSavedSettings.getBOOL("RenderParcelSelection"))
 	{
 		// Rendering is done in agent-coordinates, so need to supply
 		// an appropriate offset to the render code.
-- 
cgit v1.2.3


From 7c256e5a13dc32af12aa5c9f90a1be040e4e64e2 Mon Sep 17 00:00:00 2001
From: Richard Nelson <none@none>
Date: Mon, 11 Oct 2010 15:48:36 -0700
Subject: EXP-166 FIXED Front an Side Preset Views not accessible in Skylight
 viewer

---
 indra/newview/llbottomtray.cpp    | 2 ++
 indra/newview/llfloatercamera.cpp | 3 ---
 2 files changed, 2 insertions(+), 3 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp
index fd11045f56..758bc7be64 100644
--- a/indra/newview/llbottomtray.cpp
+++ b/indra/newview/llbottomtray.cpp
@@ -220,6 +220,8 @@ LLBottomTray::LLBottomTray(const LLSD&)
 
 	buildFromFile("panel_bottomtray.xml");
 
+	LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("CameraPresets.ChangeView", boost::bind(&LLFloaterCamera::onClickCameraItem, _2));
+
 	//this is to fix a crash that occurs because LLBottomTray is a singleton
 	//and thus is deleted at the end of the viewers lifetime, but to be cleanly
 	//destroyed LLBottomTray requires some subsystems that are long gone
diff --git a/indra/newview/llfloatercamera.cpp b/indra/newview/llfloatercamera.cpp
index be65396b0f..620e100bdf 100644
--- a/indra/newview/llfloatercamera.cpp
+++ b/indra/newview/llfloatercamera.cpp
@@ -340,9 +340,6 @@ LLFloaterCamera::LLFloaterCamera(const LLSD& val)
 	mCurrMode(CAMERA_CTRL_MODE_PAN),
 	mPrevMode(CAMERA_CTRL_MODE_PAN)
 {
-	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
-	registrar.add("CameraPresets.ChangeView", boost::bind(&LLFloaterCamera::onClickCameraItem, _2));
-
 	LLHints::registerHintTarget("view_popup", LLView::getHandle());
 }
 
-- 
cgit v1.2.3


From 34ca69949fa1bc67caa8cd0f8ed85d924303567a Mon Sep 17 00:00:00 2001
From: callum <none@none>
Date: Mon, 11 Oct 2010 16:36:59 -0700
Subject: Reworked fix for EXP-167 Add option to quit instead of going back to
 login screen

---
 indra/newview/llstartup.cpp | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index d9234425b8..9d66a7cd8a 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -232,6 +232,8 @@ 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());
@@ -707,9 +709,9 @@ bool idle_startup()
 	{
 		LL_DEBUGS("AppInit") << "Initializing Window" << LL_ENDL;
 
-		// if auto login is on and setting to quit if the login page is activated
-		// is enabled, then go ahead and exit
-		if ( show_connect_box && gSavedSettings.getBOOL("AutoLogin") && gSavedSettings.getBOOL("QuitOnLoginActivated") )
+		// 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();
@@ -792,6 +794,11 @@ bool idle_startup()
 
 	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.
 
@@ -818,6 +825,11 @@ bool idle_startup()
 			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())                                                                                  
-- 
cgit v1.2.3


From 6c7c124f4359b3147cd7441a2fca92a067026e11 Mon Sep 17 00:00:00 2001
From: callum <none@none>
Date: Tue, 12 Oct 2010 12:08:36 -0700
Subject: Viewer changes for EXP-202 Close View hint when user interacts with
 the View tools - pan or zoom

---
 indra/newview/llfloatercamera.cpp | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

(limited to 'indra/newview')

diff --git a/indra/newview/llfloatercamera.cpp b/indra/newview/llfloatercamera.cpp
index 620e100bdf..039ae83b5e 100644
--- a/indra/newview/llfloatercamera.cpp
+++ b/indra/newview/llfloatercamera.cpp
@@ -75,6 +75,8 @@ protected:
 	void	onZoomPlusHeldDown();
 	void	onZoomMinusHeldDown();
 	void	onSliderValueChanged();
+	void	onCameraTrack();
+	void	onCameraRotate();
 	F32		getOrbitRate(F32 time);
 
 private:
@@ -164,6 +166,8 @@ LLPanelCameraZoom::LLPanelCameraZoom()
 	mCommitCallbackRegistrar.add("Zoom.minus", boost::bind(&LLPanelCameraZoom::onZoomMinusHeldDown, this));
 	mCommitCallbackRegistrar.add("Zoom.plus", boost::bind(&LLPanelCameraZoom::onZoomPlusHeldDown, this));
 	mCommitCallbackRegistrar.add("Slider.value_changed", boost::bind(&LLPanelCameraZoom::onSliderValueChanged, this));
+	mCommitCallbackRegistrar.add("Camera.track", boost::bind(&LLPanelCameraZoom::onCameraTrack, this));
+	mCommitCallbackRegistrar.add("Camera.rotate", boost::bind(&LLPanelCameraZoom::onCameraRotate, this));
 }
 
 BOOL LLPanelCameraZoom::postBuild()
@@ -200,6 +204,18 @@ void LLPanelCameraZoom::onZoomMinusHeldDown()
 	gAgentCamera.setOrbitOutKey(getOrbitRate(time));
 }
 
+void LLPanelCameraZoom::onCameraTrack()
+{
+	// EXP-202 when camera panning activated, remove the hint
+	LLFirstUse::viewPopup( false );
+}
+
+void LLPanelCameraZoom::onCameraRotate()
+{
+	// EXP-202 when camera rotation activated, remove the hint
+	LLFirstUse::viewPopup( false );
+}
+
 F32 LLPanelCameraZoom::getOrbitRate(F32 time)
 {
 	if( time < NUDGE_TIME )
-- 
cgit v1.2.3


From 19be4a4d4230e5d73f50209d399c9aab7daebb4e Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Tue, 12 Oct 2010 18:47:44 -0700
Subject: EXP-188 FIXED Object Inspector flashes on and off for an item that is
 for sale

---
 indra/newview/llviewerwindow.cpp | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index b49d342126..1c0bec3047 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2948,18 +2948,20 @@ void LLViewerWindow::updateKeyboardFocus()
 
 			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->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();
@@ -2968,7 +2970,7 @@ void LLViewerWindow::updateKeyboardFocus()
 			// 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 (cur_focus->hasFocus())
+			if (!new_focus_found)
 			{
 				cur_focus->setFocus(FALSE);
 			}
-- 
cgit v1.2.3


From 867570132f3ff2dc102561e0d0950b0134dd3e53 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Tue, 12 Oct 2010 18:47:56 -0700
Subject: removed some unused settings

---
 indra/newview/app_settings/settings.xml | 187 --------------------------------
 1 file changed, 187 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index f3dea5b88b..85cfabb23c 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -3590,72 +3590,6 @@
       <key>Value</key>
       <real>0.5</real>
     </map>
-    <key>FontMonospace</key>
-    <map>
-      <key>Comment</key>
-      <string>Name of monospace font that definitely exists (Truetype file name)</string>
-      <key>Persist</key>
-      <integer>0</integer>
-      <key>Type</key>
-      <string>String</string>
-      <key>Value</key>
-      <string>DejaVuSansMono.ttf</string>
-    </map>
-    <key>FontSansSerif</key>
-    <map>
-      <key>Comment</key>
-      <string>Name of primary sans-serif font that definitely exists (Truetype file name)</string>
-      <key>Persist</key>
-      <integer>0</integer>
-      <key>Type</key>
-      <string>String</string>
-      <key>Value</key>
-      <string>MtBkLfRg.ttf</string>
-    </map>
-    <key>FontSansSerifBundledFallback</key>
-    <map>
-      <key>Comment</key>
-      <string>Name of secondary sans-serif font that definitely exists (Truetype file name)</string>
-      <key>Persist</key>
-      <integer>0</integer>
-      <key>Type</key>
-      <string>String</string>
-      <key>Value</key>
-      <string>DejaVuSansCondensed.ttf</string>
-    </map>
-    <key>FontSansSerifBold</key>
-    <map>
-      <key>Comment</key>
-      <string>Name of bold font (Truetype file name)</string>
-      <key>Persist</key>
-      <integer>0</integer>
-      <key>Type</key>
-      <string>String</string>
-      <key>Value</key>
-      <string>MtBdLfRg.ttf</string>
-    </map>
-    <key>FontSansSerifFallback</key>
-    <map>
-      <key>Comment</key>
-      <string>Name of sans-serif font (Truetype file name)</string>
-      <key>Persist</key>
-      <integer>0</integer>
-      <key>Type</key>
-      <string>String</string>
-      <key>Value</key>
-      <string />
-    </map>
-    <key>FontSansSerifFallbackScale</key>
-    <map>
-      <key>Comment</key>
-      <string>Scale of fallback font relative to huge font (fraction of huge font size)</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>F32</string>
-      <key>Value</key>
-      <real>1.0</real>
-    </map>
     <key>FontScreenDPI</key>
     <map>
       <key>Comment</key>
@@ -3667,61 +3601,6 @@
       <key>Value</key>
       <real>96.0</real>
     </map>
-    <key>FontSizeHuge</key>
-    <map>
-      <key>Comment</key>
-      <string>Size of huge font (points, or 1/72 of an inch)</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>F32</string>
-      <key>Value</key>
-      <real>16.0</real>
-    </map>
-    <key>FontSizeLarge</key>
-    <map>
-      <key>Comment</key>
-      <string>Size of large font (points, or 1/72 of an inch)</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>F32</string>
-      <key>Value</key>
-      <real>12.0</real>
-    </map>
-    <key>FontSizeMedium</key>
-    <map>
-      <key>Comment</key>
-      <string>Size of medium font (points, or 1/72 of an inch)</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>F32</string>
-      <key>Value</key>
-      <real>10.0</real>
-    </map>
-    <key>FontSizeMonospace</key>
-    <map>
-      <key>Comment</key>
-      <string>Size of monospaced font (points, or 1/72 of an inch)</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>F32</string>
-      <key>Value</key>
-      <real>8.1</real>
-    </map>
-    <key>FontSizeSmall</key>
-    <map>
-      <key>Comment</key>
-      <string>Size of small font (points, or 1/72 of an inch)</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>F32</string>
-      <key>Value</key>
-      <real>9.0</real>
-    </map>
     <key>ForceAssetFail</key>
     <map>
       <key>Comment</key>
@@ -5252,61 +5131,6 @@
       <key>Value</key>
       <real>60.0</real>
     </map>
-    <key>MeanCollisionBump</key>
-    <map>
-      <key>Comment</key>
-      <string>You have experienced an abuse of being bumped by an object or avatar</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>0</integer>
-    </map>
-    <key>MeanCollisionPhysical</key>
-    <map>
-      <key>Comment</key>
-      <string>You have experienced an abuse from a physical object</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>0</integer>
-    </map>
-    <key>MeanCollisionPushObject</key>
-    <map>
-      <key>Comment</key>
-      <string>You have experienced an abuse of being pushed by a scripted object</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>0</integer>
-    </map>
-    <key>MeanCollisionScripted</key>
-    <map>
-      <key>Comment</key>
-      <string>You have experienced an abuse from a scripted object</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>0</integer>
-    </map>
-    <key>MeanCollisionSelected</key>
-    <map>
-      <key>Comment</key>
-      <string>You have experienced an abuse of being pushed via a selected object</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>0</integer>
-    </map>
   <key>MediaControlFadeTime</key>
   <map>
     <key>Comment</key>
@@ -7836,17 +7660,6 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
-    <key>RenderFastUI</key>
-    <map>
-      <key>Comment</key>
-      <string>[NOT USED]</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>0</integer>
-    </map>
     <key>RenderFlexTimeFactor</key>
     <map>
       <key>Comment</key>
-- 
cgit v1.2.3


From 0732b48be9c6378c31515ed92d29101e3743c8c9 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Wed, 13 Oct 2010 11:57:38 -0700
Subject: improved fastquit logic which should reliably disconnect viewer from
 sim

---
 indra/newview/llappviewer.cpp    | 54 +++++++++++++++++++++-------------------
 indra/newview/llappviewer.h      |  4 +--
 indra/newview/llviewerwindow.cpp |  2 +-
 3 files changed, 32 insertions(+), 28 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 91fae709df..a245639fac 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1284,6 +1284,21 @@ bool LLAppViewer::mainLoop()
 	return true;
 }
 
+void LLAppViewer::flushVFSIO()
+{
+	while (1)
+	{
+		S32 pending = LLVFSThread::updateClass(0);
+		pending += LLLFSThread::updateClass(0);
+		if (!pending)
+		{
+			break;
+		}
+		llinfos << "Waiting for pending IO to finish: " << pending << llendflush;
+		ms_sleep(100);
+	}
+}
+
 bool LLAppViewer::cleanup()
 {
 	// workaround for DEV-35406 crash on shutdown
@@ -1419,17 +1434,7 @@ bool LLAppViewer::cleanup()
 	llinfos << "Cache files removed" << llendflush;
 
 	// Wait for any pending VFS IO
-	while (1)
-	{
-		S32 pending = LLVFSThread::updateClass(0);
-		pending += LLLFSThread::updateClass(0);
-		if (!pending)
-		{
-			break;
-		}
-		llinfos << "Waiting for pending IO to finish: " << pending << llendflush;
-		ms_sleep(100);
-	}
+	flushVFSIO();
 	llinfos << "Shutting down Views" << llendflush;
 
 	// Destroy the UI
@@ -2879,13 +2884,20 @@ void LLAppViewer::forceQuit()
 	LLApp::setQuitting(); 
 }
 
-void LLAppViewer::fastQuit()
+void LLAppViewer::fastQuit(S32 error_code)
 {
-	if (LLStartUp::getStartupState() >= STATE_STARTED)
-	{
-		sendLogoutRequest();
-	}
-	_exit(isError());	
+	// finish pending transfers
+	flushVFSIO();
+	// let sim know we're logging out
+	sendLogoutRequest();
+	// flush network buffers by shutting down messaging system
+	end_messaging_system();
+	// figure out the error code
+	S32 final_error_code = error_code ? error_code : (S32)isError();
+	// this isn't a crash	
+	removeMarkerFile();
+	// get outta here
+	_exit(final_error_code);	
 }
 
 void LLAppViewer::requestQuit()
@@ -2973,14 +2985,6 @@ void LLAppViewer::earlyExitNoNotify()
 	finish_early_exit( LLSD(), LLSD() );
 }
 
-void LLAppViewer::forceExit(S32 arg)
-{
-    removeMarkerFile();
-    
-    // *FIX:Mani - This kind of exit hardly seems appropriate.
-    exit(arg);
-}
-
 void LLAppViewer::abortQuit()
 {
     llinfos << "abortQuit()" << llendl;
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 0e7dbb738b..b2374a3426 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -65,14 +65,14 @@ public:
 	virtual bool mainLoop(); // Override for the application main loop.  Needs to at least gracefully notice the QUITTING state and exit.
 
 	// Application control
+	void flushVFSIO(); // waits for vfs transfers to complete
 	void forceQuit(); // Puts the viewer into 'shutting down without error' mode.
-	void fastQuit(); // Shuts down the viewer immediately after sending a logout message
+	void fastQuit(S32 error_code = 0); // Shuts down the viewer immediately after sending a logout message
 	void requestQuit(); // Request a quit. A kinder, gentler quit.
 	void userQuit(); // The users asks to quit. Confirm, then requestQuit()
     void earlyExit(const std::string& name, 
 				   const LLSD& substitutions = LLSD()); // Display an error dialog and forcibly quit.
 	void earlyExitNoNotify(); // Do not display error dialog then forcibly quit.
-    void forceExit(S32 arg); // exit() immediately (after some cleanup).
     void abortQuit();  // Called to abort a quit request.
 
     bool quitRequested() { return mQuitRequested; }
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 1c0bec3047..d2dab8f40c 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1371,7 +1371,7 @@ LLViewerWindow::LLViewerWindow(
 		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()->forceExit(1);
+        LLAppViewer::instance()->fastQuit(1);
 	}
 	
 	// Get the real window rect the window was created with (since there are various OS-dependent reasons why
-- 
cgit v1.2.3


From aac0d48d7d97730c95cfb541e303167a8e28d369 Mon Sep 17 00:00:00 2001
From: Monroe Linden <monroe@lindenlab.com>
Date: Wed, 13 Oct 2010 18:02:05 -0700
Subject: Fix for EXP-220 -- Remove voice dot for skylight user

Reviewed by Richard.
---
 indra/newview/llvoavatar.cpp | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index c31714de5a..7d8c1405ec 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -2326,8 +2326,19 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 
 void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
 {
-	// disable voice visualizer when in mouselook
-	mVoiceVisualizer->setVoiceEnabled( voice_enabled && !(isSelf() && gAgentCamera.cameraMouselook()) );
+	bool render_visualizer = voice_enabled;
+	
+	// Don't render the user's own voice visualizer when in mouselook, or when opening the mic is disabled.
+	if(isSelf())
+	{
+		if(gAgentCamera.cameraMouselook() || gSavedSettings.getBOOL("VoiceDisableMic"))
+		{
+			render_visualizer = false;
+		}
+	}
+	
+	mVoiceVisualizer->setVoiceEnabled(render_visualizer);
+	
 	if ( voice_enabled )
 	{		
 		//----------------------------------------------------------------
-- 
cgit v1.2.3


From 9737f2b73f75f0320079abe598bb3107d8e3668d Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Wed, 13 Oct 2010 19:21:41 -0600
Subject: fix for EXP-195: Custom login progress screen blurry when first
 presented to user as the image fully loads

---
 indra/newview/llviewertexture.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 5c262838ae..1757b6f953 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -1130,7 +1130,7 @@ void LLViewerFetchedTexture::init(bool firstinit)
 	// does not contain this image.
 	mIsMissingAsset = FALSE;
 
-	mLoadedCallbackDesiredDiscardLevel = 0;
+	mLoadedCallbackDesiredDiscardLevel = S8_MAX;
 	mPauseLoadedCallBacks = TRUE ;
 
 	mNeedsCreateTexture = FALSE;
@@ -1503,7 +1503,7 @@ void LLViewerFetchedTexture::processTextureStats()
 		}
 		else if(!mFullWidth || !mFullHeight)
 		{
-			mDesiredDiscardLevel = 	getMaxDiscardLevel() ;
+			mDesiredDiscardLevel = 	llmin(getMaxDiscardLevel(), (S32)mLoadedCallbackDesiredDiscardLevel) ;
 		}
 		else
 		{	
-- 
cgit v1.2.3


From 73b39c9b46ed25ae03b8225758c15325e50fdfe2 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Wed, 13 Oct 2010 18:41:35 -0700
Subject: made destination guide url configurable on command line

---
 indra/newview/app_settings/settings.xml | 13 ++++++++++++-
 indra/newview/llcommandlineparser.cpp   |  5 ++++-
 indra/newview/llviewerwindow.cpp        |  7 +++++++
 3 files changed, 23 insertions(+), 2 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 85cfabb23c..5c54b88927 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -2523,7 +2523,18 @@
       <key>Value</key>
       <integer>10</integer>
     </map>
-    <key>DisableCameraConstraints</key>
+    <key>DestinationGuideURL</key>
+    <map>
+      <key>Comment</key>
+      <string>Destination guide contents</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>String</string>
+      <key>Value</key>
+      <string>http://www.secondlife.com</string>
+    </map>
+  <key>DisableCameraConstraints</key>
     <map>
       <key>Comment</key>
       <string>Disable the normal bounds put on the camera by avatar position</string>
diff --git a/indra/newview/llcommandlineparser.cpp b/indra/newview/llcommandlineparser.cpp
index ee8646aad0..0b59f8bd4b 100644
--- a/indra/newview/llcommandlineparser.cpp
+++ b/indra/newview/llcommandlineparser.cpp
@@ -341,7 +341,10 @@ bool LLCommandLineParser::parseCommandLine(int argc, char **argv)
 bool LLCommandLineParser::parseCommandLineString(const std::string& str)
 {
     // Split the string content into tokens
-    boost::escaped_list_separator<char> sep("\\", "\r\n ", "\"'");
+	const char* escape_chars = "\\";
+	const char* separator_chars = "\r\n ";
+	const char* quote_chars = "\"'";
+    boost::escaped_list_separator<char> sep(escape_chars, separator_chars, quote_chars);
     boost::tokenizer< boost::escaped_list_separator<char> > tok(str, sep);
     std::vector<std::string> tokens;
     // std::copy(tok.begin(), tok.end(), std::back_inserter(tokens));
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index d2dab8f40c..b1d8e2f353 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1698,6 +1698,13 @@ void LLViewerWindow::initWorldUI()
 	buttons_panel->setShape(buttons_panel_container->getLocalRect());
 	buttons_panel->setFollowsAll();
 	buttons_panel_container->addChild(buttons_panel);
+
+	LLView* destination_guide = gViewerWindow->getRootView()->getChild<LLView>("destination_guide_container");
+	LLMediaCtrl* destinations = destination_guide->findChild<LLMediaCtrl>("destination_guide_contents");
+	if (destinations)
+	{
+		destinations->navigateTo(gSavedSettings.getString("DestinationGuideURL"));
+	}
 }
 
 // Destroy the UI
-- 
cgit v1.2.3


From 8b9b7fed7367eeb7b055f7b2a44a37539634045e Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Thu, 14 Oct 2010 13:31:54 -0700
Subject: removed fastquit

---
 indra/newview/app_settings/settings.xml | 11 -----------
 indra/newview/llappviewer.cpp           |  6 +-----
 indra/newview/llappviewerwin32.cpp      |  6 ------
 3 files changed, 1 insertion(+), 22 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 5c54b88927..f8bd6fa3b9 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -2995,17 +2995,6 @@
         <string>Boolean</string>
         <key>Value</key>
         <integer>0</integer>
-    </map>
-    <key>FastQuit</key>
-      <map>
-        <key>Comment</key>
-        <string>Quits as quickly as possible, only sending logout request before forcefully terminating.  Use with care, as this might result in data corruption or loss.</string>
-        <key>Persist</key>
-        <integer>1</integer>
-        <key>Type</key>
-        <string>Boolean</string>
-        <key>Value</key>
-        <integer>0</integer>
     </map>
 	<key>FeatureManagerHTTPTable</key>
       <map>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index a245639fac..39c3181cdc 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2884,6 +2884,7 @@ void LLAppViewer::forceQuit()
 	LLApp::setQuitting(); 
 }
 
+//TODO: remove
 void LLAppViewer::fastQuit(S32 error_code)
 {
 	// finish pending transfers
@@ -2902,11 +2903,6 @@ void LLAppViewer::fastQuit(S32 error_code)
 
 void LLAppViewer::requestQuit()
 {
-	if (gSavedSettings.getBOOL("FastQuit"))
-	{
-		fastQuit();
-	}
-
 	llinfos << "requestQuit" << llendl;
 
 	LLViewerRegion* region = gAgent.getRegion();
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index 2c6f014d17..d328567a0e 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -175,12 +175,6 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,
 		viewer_app_ptr->mainLoop();
 	}
 
-	if (gSavedSettings.getBOOL("FastQuit"))
-	{
-		viewer_app_ptr->fastQuit();
-	}
-
-
 	if (!LLApp::isError())
 	{
 		//
-- 
cgit v1.2.3


From eea2b8f9d3fe909befd43ca8db7878855ddd661d Mon Sep 17 00:00:00 2001
From: callum <none@none>
Date: Thu, 14 Oct 2010 15:18:00 -0700
Subject: EXP-225 FIX Add debug setting to quit the viewer after N seconds of
 AFK behavior. Viewer specific setting for this feature including default
 value in settings file

---
 indra/newview/app_settings/settings.xml | 11 +++++++++++
 indra/newview/llappviewer.cpp           | 12 ++++++++++++
 2 files changed, 23 insertions(+)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 5c54b88927..7538b152c1 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -6403,6 +6403,17 @@
       <key>Value</key>
       <real>0.0</real>
     </map>
+    <key>QuitAfterSecondsOfAFK</key>
+    <map>
+      <key>Comment</key>
+      <string>The duration allowed after being AFK before quitting.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>F32</string>
+      <key>Value</key>
+      <real>0.0</real>
+    </map>
     <key>QuitOnLoginActivated</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index a245639fac..ba3c6a5916 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -3569,6 +3569,18 @@ void LLAppViewer::idle()
 		}
 	}
 
+	// debug setting to quit after N seconds of being AFK - 0 to never do this
+	F32 qas_afk = gSavedSettings.getF32("QuitAfterSecondsOfAFK");
+	if (qas_afk > 0.f)
+	{
+		// idle time is more than setting
+		if ( gAwayTriggerTimer.getElapsedTimeF32() > qas_afk )
+		{
+			// go ahead and just quit
+			LLAppViewer::instance()->forceQuit();
+		}
+	}
+
 	// Must wait until both have avatar object and mute list, so poll
 	// here.
 	request_initial_instant_messages();
-- 
cgit v1.2.3


From 7df167129955f2f44b2048f1e8e89c685f2b7485 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Fri, 15 Oct 2010 14:05:11 -0700
Subject: EXP-229 FIXED Double clicking x on UI hint crashes Skylight Viewer

---
 indra/newview/llhints.cpp | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llhints.cpp b/indra/newview/llhints.cpp
index 5ffc4ace59..8edc42e15c 100644
--- a/indra/newview/llhints.cpp
+++ b/indra/newview/llhints.cpp
@@ -112,7 +112,14 @@ public:
 
 	/*virtual*/ BOOL postBuild();
 
-	void onClickClose() { hide(); LLNotifications::instance().cancel(mNotification); }
+	void onClickClose() 
+	{ 
+		if (!mHidden) 
+		{
+			hide(); 
+			LLNotifications::instance().cancel(mNotification);
+		}
+	}
 	void draw();
 	void hide() { if(!mHidden) {mHidden = true; mFadeTimer.reset();} }
 
-- 
cgit v1.2.3


From 6dcf769ca5c8bef9a170451094f022ac3791f1d9 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Fri, 15 Oct 2010 14:05:27 -0700
Subject: added schema to settings.xml

---
 indra/newview/app_settings/llsd.xsd     | 131 ++++++++++++++++++++++++++++++++
 indra/newview/app_settings/settings.xml |   3 +-
 2 files changed, 133 insertions(+), 1 deletion(-)
 create mode 100644 indra/newview/app_settings/llsd.xsd

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/llsd.xsd b/indra/newview/app_settings/llsd.xsd
new file mode 100644
index 0000000000..34612d9faa
--- /dev/null
+++ b/indra/newview/app_settings/llsd.xsd
@@ -0,0 +1,131 @@
+<?xml version="1.0"?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+
+        <!-- LLSD document has exactly one value -->
+	<xsd:element name="llsd">
+		<xsd:complexType>                        
+                        <xsd:group ref="llsd-value" />
+		</xsd:complexType>
+	</xsd:element>
+
+        <!-- Value is one of undef, boolean, integer, real, 
+             uuid, string, date, binary, array, or map -->
+        <xsd:group name="llsd-value">
+                <xsd:choice>
+        		<xsd:element ref="undef"/>
+        		<xsd:element ref="boolean"/>
+        		<xsd:element ref="integer"/>
+        		<xsd:element ref="real"/>
+        		<xsd:element ref="uuid"/>
+        		<xsd:element ref="string"/>
+        		<xsd:element ref="date"/>
+			<xsd:element ref="uri"/>
+			<xsd:element ref="binary"/>
+			<xsd:element ref="array"/>
+			<xsd:element ref="map"/>
+                </xsd:choice>
+        </xsd:group>
+
+        <!-- Undefined is an empty eleemnt -->
+	<xsd:element name="undef">
+		<xsd:simpleType>
+                        <xsd:restriction base="xsd:string">
+                             <xsd:length value="0" />
+                        </xsd:restriction>
+                </xsd:simpleType>
+        </xsd:element>
+
+        <!-- Boolean is true or false -->
+	<xsd:element name="boolean">
+		<xsd:simpleType>
+			<xsd:restriction base="xsd:string">
+				<xsd:enumeration value="true" />
+				<xsd:enumeration value="false" />
+
+                                <!-- In practice, these other serializations are seen: -->
+				<xsd:enumeration value="" />
+				<xsd:enumeration value="1" />
+				<xsd:enumeration value="0" />
+			</xsd:restriction>
+		</xsd:simpleType>
+	</xsd:element>
+
+        <!-- Integer is restricted to 32-bit signed values -->
+	<xsd:element name="integer">
+		<xsd:simpleType>
+			<xsd:restriction base="xsd:int" />
+		</xsd:simpleType>
+	</xsd:element>
+
+        <!-- Real is an IEEE 754 "double" value, including Infinities and NaN -->
+	<xsd:element name="real">
+		<xsd:simpleType>
+                        <!-- TODO: xsd:double uses "INF", "-INF", and "NaN",
+                        whereas LLSD prefers "Infinity", "-Infinity" and "NaN" -->
+			<xsd:restriction base="xsd:double" />
+		</xsd:simpleType>
+	</xsd:element>
+
+        <!-- UUID per RFC 4122 -->
+	<xsd:element name="uuid">
+		<xsd:simpleType>
+			<xsd:restriction base="xsd:string">
+				<xsd:pattern value="[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|" />
+			</xsd:restriction>
+		</xsd:simpleType>
+	</xsd:element>
+
+        <!-- String is any sequence of Unicode characters -->
+	<xsd:element name="string">
+		<xsd:simpleType>
+			<xsd:restriction base="xsd:string" />
+		</xsd:simpleType>
+	</xsd:element>
+
+        <!-- Date is ISO 8601 in UTC -->
+	<xsd:element name="date">
+		<xsd:simpleType>
+			<xsd:restriction base="xsd:dateTime">
+                                <!-- Restrict to UTC (Z) times -->
+                                <xsd:pattern value="[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?Z" />
+			</xsd:restriction>
+		</xsd:simpleType>
+	</xsd:element>
+
+        <!-- URI per RFC 3986 -->
+	<xsd:element name="uri">
+		<xsd:simpleType>
+			<xsd:restriction base="xsd:anyURI" />
+		</xsd:simpleType>
+	</xsd:element>
+
+        <!-- Binary data is base64 encoded -->
+	<xsd:element name="binary">
+		<xsd:simpleType>
+                        <!-- TODO: Require encoding attribute? -->
+			<xsd:restriction base="xsd:base64Binary" />
+		</xsd:simpleType>
+	</xsd:element>
+
+        <!-- Array is a sequence of zero or more values -->
+	<xsd:element name="array">
+		<xsd:complexType>
+                        <xsd:group minOccurs="0" maxOccurs="unbounded" ref="llsd-value" />
+		</xsd:complexType>
+	</xsd:element>
+
+        <!-- Map is a sequence of zero or more key/value pairs -->
+	<xsd:element name="map">
+		<xsd:complexType>
+			<xsd:sequence minOccurs="0" maxOccurs="unbounded">
+				<xsd:element name="key">
+                                	<xsd:simpleType>
+                                        	<xsd:restriction base="xsd:string" />
+                                        </xsd:simpleType>
+				</xsd:element>
+                                <xsd:group ref="llsd-value" />
+			</xsd:sequence>
+		</xsd:complexType>
+	</xsd:element>
+
+</xsd:schema>
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 36ac7ecf99..37e1db20ff 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" ?>
-<llsd>
+<llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:noNamespaceSchemaLocation="llsd.xsd">
 <map>
 	<key>CrashHostUrl</key>
     <map>
-- 
cgit v1.2.3


From a5bf17539846834d3e30eb16cae66b313b2dd060 Mon Sep 17 00:00:00 2001
From: callum <none@none>
Date: Fri, 15 Oct 2010 14:57:29 -0700
Subject: EXP-225 FIX Add debug setting to quit the viewer after N seconds of
 AFK behavior. This change makes the logout process less aggressive so zombie
 sessions do not get left behind

---
 indra/newview/llappviewer.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 61599ad435..ca2503c447 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -3572,8 +3572,8 @@ void LLAppViewer::idle()
 		// idle time is more than setting
 		if ( gAwayTriggerTimer.getElapsedTimeF32() > qas_afk )
 		{
-			// go ahead and just quit
-			LLAppViewer::instance()->forceQuit();
+			// go ahead and just quit gracefully
+			LLAppViewer::instance()->requestQuit();
 		}
 	}
 
-- 
cgit v1.2.3


From 1aea5210165a3e7d0467b5107de4a94d5b5c3be4 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Fri, 15 Oct 2010 16:29:45 -0700
Subject: fix for dead space at top of screen where media hud is not clickable

---
 indra/newview/llviewerwindow.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index b1d8e2f353..9f272fc845 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1669,7 +1669,7 @@ void LLViewerWindow::initWorldUI()
 	{
 		LLRect hud_rect = full_window;
 		hud_rect.mBottom += 50;
-		if (gMenuBarView)
+		if (gMenuBarView && gMenuBarView->isInVisibleChain())
 		{
 			hud_rect.mTop -= gMenuBarView->getRect().getHeight();
 		}
-- 
cgit v1.2.3


From 97101982de2b434582a795e7d81c32010bed9c13 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Mon, 18 Oct 2010 17:24:49 -0700
Subject: EXP-250 FIX Option to disable beacons

---
 indra/newview/app_settings/settings.xml | 11 +++++++++++
 indra/newview/lltracker.cpp             |  2 +-
 2 files changed, 12 insertions(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 37e1db20ff..f316909990 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -8154,6 +8154,17 @@
       <key>Value</key>
       <real>1.0</real>
     </map>
+    <key>RenderTrackerBeacon</key>
+      <map>
+      <key>Comment</key>
+      <string>Display tracking arrow and beacon to target avatar/teleport destination</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
     <key>RenderTreeLODFactor</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/lltracker.cpp b/indra/newview/lltracker.cpp
index 8391c0f832..7ce19b528a 100644
--- a/indra/newview/lltracker.cpp
+++ b/indra/newview/lltracker.cpp
@@ -155,7 +155,7 @@ void LLTracker::drawHUDArrow()
 // static 
 void LLTracker::render3D()
 {
-	if (!gFloaterWorldMap)
+	if (!gFloaterWorldMap || !gSavedSettings.getBOOL("RenderTrackerBeacon"))
 	{
 		return;
 	}
-- 
cgit v1.2.3


From 548f2e92ffd8e971c379860c77d76f1b26313ee5 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Mon, 18 Oct 2010 17:34:30 -0700
Subject: EXP-250 FIX Option to disable beacons hud arrow also controlled by
 RenderTrackerBeacon setting

---
 indra/newview/app_settings/settings.xml | 4 ++--
 indra/newview/lltracker.cpp             | 2 ++
 2 files changed, 4 insertions(+), 2 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index f316909990..7788d6b2a0 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -8155,9 +8155,9 @@
       <real>1.0</real>
     </map>
     <key>RenderTrackerBeacon</key>
-      <map>
+    <map>
       <key>Comment</key>
-      <string>Display tracking arrow and beacon to target avatar/teleport destination</string>
+      <string>Display tracking arrow and beacon to target avatar, teleport destination</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
diff --git a/indra/newview/lltracker.cpp b/indra/newview/lltracker.cpp
index 7ce19b528a..61ea4bb0e6 100644
--- a/indra/newview/lltracker.cpp
+++ b/indra/newview/lltracker.cpp
@@ -109,6 +109,8 @@ void LLTracker::stopTracking(void* userdata)
 // static virtual
 void LLTracker::drawHUDArrow()
 {
+	if (!gSavedSettings.getBOOL("RenderTrackerBeacon")) return;
+
 	static LLUIColor map_track_color = LLUIColorTable::instance().getColor("MapTrackColor", LLColor4::white);
 	
 	/* tracking autopilot destination has been disabled 
-- 
cgit v1.2.3


From a2009170c92ecb56cf304447dbedfeef74272c0d Mon Sep 17 00:00:00 2001
From: callum <none@none>
Date: Tue, 19 Oct 2010 14:06:23 -0700
Subject: EXP-258	FIX Help url is overwritten by login.cgi Settings have
 to be persistent otherwise the layering mechanism doesn't work

---
 indra/newview/app_settings/settings.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 7788d6b2a0..f53c060c1f 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -3794,7 +3794,7 @@
       <key>Comment</key>
       <string>URL pattern for help page; arguments will be encoded; see llviewerhelp.cpp:buildHelpURL for arguments</string>
       <key>Persist</key>
-      <integer>0</integer>
+      <integer>1</integer>
       <key>Type</key>
       <string>String</string>
       <key>Value</key>
-- 
cgit v1.2.3


From 2a2256e8b06dfcefa10f32bf2c6775df19dfc782 Mon Sep 17 00:00:00 2001
From: Monroe Linden <monroe@lindenlab.com>
Date: Tue, 19 Oct 2010 16:44:09 -0700
Subject: Fix for EXP-201 -- "Clean shutdown"

Reviewed by Brad and Mani.
---
 indra/newview/llappviewer.cpp | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index ca2503c447..d658ad5c0e 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2909,6 +2909,13 @@ void LLAppViewer::requestQuit()
 	
 	if( (LLStartUp::getStartupState() < STATE_STARTED) || !region )
 	{
+		// If we have a region, make some attempt to send a logout request first.
+		// This prevents the halfway-logged-in avatar from hanging around inworld for a couple minutes.
+		if(region)
+		{
+			sendLogoutRequest();
+		}
+		
 		// Quit immediately
 		forceQuit();
 		return;
@@ -4012,7 +4019,10 @@ void LLAppViewer::sendLogoutRequest()
 		gLogoutMaxTime = LOGOUT_REQUEST_TIME;
 		mLogoutRequestSent = TRUE;
 		
-		LLVoiceClient::getInstance()->leaveChannel();
+		if(LLVoiceClient::instanceExists())
+		{
+			LLVoiceClient::getInstance()->leaveChannel();
+		}
 
 		//Set internal status variables and marker files
 		gLogoutInProgress = TRUE;
-- 
cgit v1.2.3


From a0e3c4380d3cbfbb5e0589d081a7068c1525ebce Mon Sep 17 00:00:00 2001
From: callum <none@none>
Date: Thu, 21 Oct 2010 16:55:15 -0700
Subject: EXP-271 FIX Implement slapp functionality for changing avatars

---
 indra/newview/llappearancemgr.cpp | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

(limited to 'indra/newview')

diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index ed5e8ceee3..8737e97b47 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -2943,3 +2943,32 @@ void wear_multiple(const uuid_vec_t& ids, bool replace)
 	}
 }
 
+// SLapp for easy-wearing of a stock (library) avatar
+//
+class LLWearFolderHandler : public LLCommandHandler
+{
+public:
+	// not allowed from outside the app
+	LLWearFolderHandler() : LLCommandHandler("wear_folder", UNTRUSTED_BLOCK) { }
+
+	bool handle(const LLSD& tokens, const LLSD& query_map,
+				LLMediaCtrl* web)
+	{
+		LLPointer<LLInventoryCategory> category = new LLInventoryCategory(query_map["folder_id"],
+																		  LLUUID::null,
+																		  LLFolderType::FT_CLOTHING,
+																		  "Quick Appearance");
+		LLSD::UUID folder_uuid = query_map["folder_id"].asUUID();
+		if ( gInventory.getCategory( folder_uuid ) != NULL )
+		{
+			LLAppearanceMgr::getInstance()->wearInventoryCategory(category, true, false);
+
+			// *TODOw: This may not be necessary if initial outfit is chosen already -- josh
+			gAgent.setGenderChosen(TRUE);
+		}
+
+		return true;
+	}
+};
+
+LLWearFolderHandler gWearFolderHandler;
-- 
cgit v1.2.3


From e638204dc2d8b409f17f7cdf8938deb97d137dbc Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Thu, 21 Oct 2010 17:14:14 -0700
Subject: EXP-273 WIP added avatar picker popup and hint

---
 indra/newview/app_settings/ignorable_dialogs.xml   | 11 +++++++
 indra/newview/app_settings/settings.xml            | 11 +++++++
 indra/newview/llbottomtray.cpp                     |  1 +
 indra/newview/llfirstuse.cpp                       |  7 +++++
 indra/newview/llfirstuse.h                         |  1 +
 indra/newview/llviewermenu.cpp                     | 36 +++++++++++++++-------
 indra/newview/llviewerwindow.cpp                   |  4 +++
 .../newview/skins/default/xui/en/notifications.xml |  8 +++++
 8 files changed, 68 insertions(+), 11 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/ignorable_dialogs.xml b/indra/newview/app_settings/ignorable_dialogs.xml
index f800d836fa..505d852587 100644
--- a/indra/newview/app_settings/ignorable_dialogs.xml
+++ b/indra/newview/app_settings/ignorable_dialogs.xml
@@ -23,6 +23,17 @@
     <key>Value</key>
     <integer>1</integer>
   </map>
+  <key>FirstNotUseAvatarPicker</key>
+  <map>
+    <key>Comment</key>
+    <string>Shows hint when resident doesn't activate avatar picker</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>1</integer>
+  </map>
   <key>FirstNotUseSidePanel</key>
   <map>
     <key>Comment</key>
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index f53c060c1f..f23b57e62c 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -12069,6 +12069,17 @@
       <key>Value</key>
       <real>1200.0</real>
     </map>
+    <key>AvatarPickerHintTimeout</key>
+    <map>
+      <key>Comment</key>
+      <string>Number of seconds to wait before telling resident about avatar picker.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>F32</string>
+      <key>Value</key>
+      <real>600.0</real>
+    </map>
     <key>SidePanelHintTimeout</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp
index 758bc7be64..1ba2a69289 100644
--- a/indra/newview/llbottomtray.cpp
+++ b/indra/newview/llbottomtray.cpp
@@ -521,6 +521,7 @@ BOOL LLBottomTray::postBuild()
 {
 	LLHints::registerHintTarget("bottom_tray", LLView::getHandle());
 	LLHints::registerHintTarget("dest_guide_btn", getChild<LLUICtrl>("destinations_btn")->getHandle());
+	LLHints::registerHintTarget("avatar_picker_btn", getChild<LLUICtrl>("avatar_picker_btn")->getHandle());
 
 	LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("NearbyChatBar.Action", boost::bind(&LLBottomTray::onContextMenuItemClicked, this, _2));
 	LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("NearbyChatBar.EnableMenuItem", boost::bind(&LLBottomTray::onContextMenuItemEnabled, this, _2));
diff --git a/indra/newview/llfirstuse.cpp b/indra/newview/llfirstuse.cpp
index 5d6197c688..e12a8c2528 100644
--- a/indra/newview/llfirstuse.cpp
+++ b/indra/newview/llfirstuse.cpp
@@ -103,6 +103,13 @@ void LLFirstUse::notUsingDestinationGuide(bool enable)
 	firstUseNotification("FirstNotUseDestinationGuide", enable, "HintDestinationGuide", LLSD(), LLSD().with("target", "dest_guide_btn").with("direction", "top"));
 }
 
+void LLFirstUse::notUsingAvatarPicker(bool enable)
+{
+	// not doing this yet
+	firstUseNotification("FirstNotUseAvatarPicker", enable, "HintAvatarPicker", LLSD(), LLSD().with("target", "avatar_picker_btn").with("direction", "top"));
+}
+
+
 // static
 void LLFirstUse::notUsingSidePanel(bool enable)
 {
diff --git a/indra/newview/llfirstuse.h b/indra/newview/llfirstuse.h
index 3886df4ee9..04783544b9 100644
--- a/indra/newview/llfirstuse.h
+++ b/indra/newview/llfirstuse.h
@@ -87,6 +87,7 @@ public:
 	static void otherAvatarChatFirst(bool enable = true);
 	static void sit(bool enable = true);
 	static void notUsingDestinationGuide(bool enable = true);
+	static void notUsingAvatarPicker(bool enable = true);
 	static void notUsingSidePanel(bool enable = true);
 	static void notMoving(bool enable = true);
 	static void viewPopup(bool enable = true);
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 0454d4a249..ca9cc8e987 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -847,24 +847,37 @@ class LLAdvancedCheckFeature : public view_listener_t
 void LLDestinationGuideToggle()
 {
 	LLView* destination_guide = gViewerWindow->getRootView()->getChildView("destination_guide_container");
-	if ( destination_guide )
+	LLView* avatar_picker = gViewerWindow->getRootView()->getChildView("avatar_picker_container");
+
+	if ( destination_guide->getVisible() )
 	{
-		if ( destination_guide->getVisible() )
-		{
-			destination_guide->setVisible( FALSE );
-		}
-		else
-		{
-			LLFirstUse::notUsingDestinationGuide(false);
-			destination_guide->setVisible( true );
-		}
+		destination_guide->setVisible( FALSE );
+	}
+	else
+	{
+		LLFirstUse::notUsingDestinationGuide(false);
+		destination_guide->setVisible( true );
+		avatar_picker->setVisible( false );
+	}
+};
+
+void LLAvatarPickerToggle()
+{
+	LLView* avatar_picker = gViewerWindow->getRootView()->getChildView("avatar_picker_container");
+	LLView* destination_guide = gViewerWindow->getRootView()->getChildView("destination_guide_container");
+	if ( avatar_picker->getVisible() )
+	{
+		avatar_picker->setVisible( false );
 	}
 	else
 	{
-		llwarns << "ERROR: unable to find destination guide container" << llendl;
+		LLFirstUse::notUsingAvatarPicker(false);
+		avatar_picker->setVisible( true );
+		destination_guide->setVisible( false );
 	}
 };
 
+
 //////////////////
 // INFO DISPLAY //
 //////////////////
@@ -8297,4 +8310,5 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLToggleUIHints(), "ToggleUIHints");
 
 	commit.add("DestinationGuide.toggle", boost::bind(&LLDestinationGuideToggle));
+	commit.add("AvatarPicker.toggle", boost::bind(&LLAvatarPickerToggle));
 }
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 9f272fc845..62e8f4223e 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2460,6 +2460,10 @@ void LLViewerWindow::updateUI()
 		{
 			LLFirstUse::notUsingDestinationGuide();
 		}
+		if (gLoggedInTime.getElapsedTimeF32() > gSavedSettings.getF32("AvatarPickerHintTimeout"))
+		{
+			LLFirstUse::notUsingAvatarPicker();
+		}
 		if (gLoggedInTime.getElapsedTimeF32() > gSavedSettings.getF32("SidePanelHintTimeout"))
 		{
 			LLFirstUse::notUsingSidePanel();
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 834fe6f966..b32a33b59a 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -6447,6 +6447,14 @@ Mute everyone?
     The Destination Guide contains thousands of new places to discover. Select a location and choose Teleport to start exploring.
   </notification>
 
+  <notification
+  name="HintAvatarPicker"
+  label="Change your Look"
+  type="hint"
+  unique="true">
+    Would you like to try a new look?  Click the button below to see more Avatars.
+  </notification>
+
   <notification
     name="HintSidePanel"
     label="Side Panel"
-- 
cgit v1.2.3


From 90168d285bfa0250cab6709eb3be8d6f2517011a Mon Sep 17 00:00:00 2001
From: Monty Brandenberg <monty@lindenlab.com>
Date: Fri, 22 Oct 2010 09:10:44 -0700
Subject: ESC-108 Develop support classes for numerical collection Stuff moved
 over and adapted from simulator code.  Basic, simple counters and
 min/max/mean accumulators.

---
 indra/newview/CMakeLists.txt              |   5 +
 indra/newview/llsimplestat.h              | 140 ++++++++++
 indra/newview/tests/llsimplestat_test.cpp | 428 ++++++++++++++++++++++++++++++
 3 files changed, 573 insertions(+)
 create mode 100644 indra/newview/llsimplestat.h
 create mode 100644 indra/newview/tests/llsimplestat_test.cpp

(limited to 'indra/newview')

diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 1f4302d870..0c4d2aaca6 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1925,6 +1925,11 @@ if (LL_TESTS)
     "${test_libs}"
     )
 
+  LL_ADD_INTEGRATION_TEST(llsimplestat
+	""
+    "${test_libs}"
+    )
+
   #ADD_VIEWER_BUILD_TEST(llmemoryview viewer)
   #ADD_VIEWER_BUILD_TEST(llagentaccess viewer)
   #ADD_VIEWER_BUILD_TEST(llworldmap viewer)
diff --git a/indra/newview/llsimplestat.h b/indra/newview/llsimplestat.h
new file mode 100644
index 0000000000..f8f4be0390
--- /dev/null
+++ b/indra/newview/llsimplestat.h
@@ -0,0 +1,140 @@
+/** 
+ * @file llsimplestat.h
+ * @brief Runtime statistics accumulation.
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ * 
+ * Copyright (c) 2010, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_SIMPLESTAT_H
+#define LL_SIMPLESTAT_H
+
+// History
+//
+// The original source for this code is the server repositories'
+// llcommon/llstat.h file.  This particular code was added after the
+// viewer/server code schism but before the effort to convert common
+// code to libraries was complete.  Rather than add to merge issues,
+// the needed code was cut'n'pasted into this new header as it isn't
+// too awful a burden.  Post-modularization, we can look at removing
+// this redundancy.
+
+
+/**
+ * @class LLSimpleStatCounter
+ * @brief Just counts events.
+ *
+ * Really not needed but have a pattern in mind in the future.
+ * Interface limits what can be done at that's just fine.
+ *
+ * *TODO:  Update/transfer unit tests
+ * Unit tests:  indra/test/llcommon_llstat_tut.cpp
+ */
+class LLSimpleStatCounter
+{
+public:
+	inline LLSimpleStatCounter()		{ reset(); }
+	// Default destructor and assignment operator are valid
+
+	inline void reset()					{ mCount = 0; }
+
+	inline U32 operator++()				{ return ++mCount; }
+
+	inline U32 getCount() const			{ return mCount; }
+		
+protected:
+	U32			mCount;
+};
+
+
+/**
+ * @class LLSimpleStatMMM
+ * @brief Templated collector of min, max and mean data for stats.
+ *
+ * Fed a stream of data samples, keeps a running account of the
+ * min, max and mean seen since construction or the last reset()
+ * call.  A freshly-constructed or reset instance returns counts
+ * and values of zero.
+ *
+ * Overflows and underflows (integer, inf or -inf) and NaN's
+ * are the caller's problem.  As is loss of precision when
+ * the running sum's exponent (when parameterized by a floating
+ * point of some type) differs from a given data sample's.
+ *
+ * Unit tests:  indra/test/llcommon_llstat_tut.cpp
+ */
+template <typename VALUE_T = F32>
+class LLSimpleStatMMM
+{
+public:
+	typedef VALUE_T Value;
+	
+public:
+	LLSimpleStatMMM()				{ reset(); }
+	// Default destructor and assignment operator are valid
+
+	/**
+	 * Resets the object returning all counts and derived
+	 * values back to zero.
+	 */
+	void reset()
+		{
+			mCount = 0;
+			mMin = Value(0);
+			mMax = Value(0);
+			mTotal = Value(0);
+		}
+
+	void record(Value v)
+		{
+			if (mCount)
+			{
+				mMin = llmin(mMin, v);
+				mMax = llmax(mMax, v);
+			}
+			else
+			{
+				mMin = v;
+				mMax = v;
+			}
+			mTotal += v;
+			++mCount;
+		}
+
+	inline U32 getCount() const		{ return mCount; }
+	inline Value getMin() const		{ return mMin; }
+	inline Value getMax() const		{ return mMax; }
+	inline Value getMean() const	{ return mCount ? mTotal / mCount : mTotal; }
+		
+protected:
+	U32			mCount;
+	Value		mMin;
+	Value		mMax;
+	Value		mTotal;
+};
+
+#endif // LL_SIMPLESTAT_H
diff --git a/indra/newview/tests/llsimplestat_test.cpp b/indra/newview/tests/llsimplestat_test.cpp
new file mode 100644
index 0000000000..5efc9cf857
--- /dev/null
+++ b/indra/newview/tests/llsimplestat_test.cpp
@@ -0,0 +1,428 @@
+/** 
+ * @file llsimplestats_test.cpp
+ * @date 2010-10-22
+ * @brief Test cases for some of llsimplestat.h
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ * 
+ * Copyright (c) 2010, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include <tut/tut.hpp>
+
+#include "lltut.h"
+#include "../llsimplestat.h"
+#include "llsd.h"
+#include "llmath.h"
+
+// @brief Used as a pointer cast type to get access to LLSimpleStatCounter
+class TutStatCounter: public LLSimpleStatCounter
+{
+public:
+	TutStatCounter();							// Not defined
+	~TutStatCounter();							// Not defined
+	void operator=(const TutStatCounter &);		// Not defined
+	
+	void setRawCount(U32 c)				{ mCount = c; }
+	U32 getRawCount() const				{ return mCount; }
+};
+
+
+namespace tut
+{
+	struct stat_counter_index
+	{};
+	typedef test_group<stat_counter_index> stat_counter_index_t;
+	typedef stat_counter_index_t::object stat_counter_index_object_t;
+	tut::stat_counter_index_t tut_stat_counter_index("stat_counter_test");
+
+	// Testing LLSimpleStatCounter's external interface
+	template<> template<>
+	void stat_counter_index_object_t::test<1>()
+	{
+		LLSimpleStatCounter c1;
+		ensure("Initialized counter is zero", (0 == c1.getCount()));
+
+		ensure("Counter increment return is 1", (1 == ++c1));
+		ensure("Counter increment return is 2", (2 == ++c1));
+
+		ensure("Current counter is 2", (2 == c1.getCount()));
+
+		c1.reset();
+		ensure("Counter is 0 after reset", (0 == c1.getCount()));
+		
+		ensure("Counter increment return is 1", (1 == ++c1));
+	}
+
+	// Testing LLSimpleStatCounter's internal state
+	template<> template<>
+	void stat_counter_index_object_t::test<2>()
+	{
+		LLSimpleStatCounter c1;
+		TutStatCounter * tc1 = (TutStatCounter *) &c1;
+		
+		ensure("Initialized private counter is zero", (0 == tc1->getRawCount()));
+
+		++c1;
+		++c1;
+		
+		ensure("Current private counter is 2", (2 == tc1->getRawCount()));
+
+		c1.reset();
+		ensure("Raw counter is 0 after reset", (0 == tc1->getRawCount()));
+	}
+
+	// Testing LLSimpleStatCounter's wrapping behavior
+	template<> template<>
+	void stat_counter_index_object_t::test<3>()
+	{
+		LLSimpleStatCounter c1;
+		TutStatCounter * tc1 = (TutStatCounter *) &c1;
+
+		tc1->setRawCount(U32_MAX);
+		ensure("Initialized private counter is zero", (U32_MAX == c1.getCount()));
+
+		ensure("Increment of max value wraps to 0", (0 == ++c1));
+	}
+
+	// Testing LLSimpleStatMMM's external behavior
+	template<> template<>
+	void stat_counter_index_object_t::test<4>()
+	{
+		LLSimpleStatMMM<> m1;
+		typedef LLSimpleStatMMM<>::Value lcl_float;
+		lcl_float zero(0);
+
+		// Freshly-constructed
+		ensure("Constructed MMM<> has 0 count", (0 == m1.getCount()));
+		ensure("Constructed MMM<> has 0 min", (zero == m1.getMin()));
+		ensure("Constructed MMM<> has 0 max", (zero == m1.getMax()));
+		ensure("Constructed MMM<> has 0 mean no div-by-zero", (zero == m1.getMean()));
+
+		// Single insert
+		m1.record(1.0);
+		ensure("Single insert MMM<> has 1 count", (1 == m1.getCount()));
+		ensure("Single insert MMM<> has 1.0 min", (1.0 == m1.getMin()));
+		ensure("Single insert MMM<> has 1.0 max", (1.0 == m1.getMax()));
+		ensure("Single insert MMM<> has 1.0 mean", (1.0 == m1.getMean()));
+		
+		// Second insert
+		m1.record(3.0);
+		ensure("2nd insert MMM<> has 2 count", (2 == m1.getCount()));
+		ensure("2nd insert MMM<> has 1.0 min", (1.0 == m1.getMin()));
+		ensure("2nd insert MMM<> has 3.0 max", (3.0 == m1.getMax()));
+		ensure_approximately_equals("2nd insert MMM<> has 2.0 mean", m1.getMean(), lcl_float(2.0), 1);
+
+		// Third insert
+		m1.record(5.0);
+		ensure("3rd insert MMM<> has 3 count", (3 == m1.getCount()));
+		ensure("3rd insert MMM<> has 1.0 min", (1.0 == m1.getMin()));
+		ensure("3rd insert MMM<> has 5.0 max", (5.0 == m1.getMax()));
+		ensure_approximately_equals("3rd insert MMM<> has 3.0 mean", m1.getMean(), lcl_float(3.0), 1);
+
+		// Fourth insert
+		m1.record(1000000.0);
+		ensure("4th insert MMM<> has 4 count", (4 == m1.getCount()));
+		ensure("4th insert MMM<> has 1.0 min", (1.0 == m1.getMin()));
+		ensure("4th insert MMM<> has 100000.0 max", (1000000.0 == m1.getMax()));
+		ensure_approximately_equals("4th insert MMM<> has 250002.0 mean", m1.getMean(), lcl_float(250002.0), 1);
+
+		// Reset
+		m1.reset();
+		ensure("Reset MMM<> has 0 count", (0 == m1.getCount()));
+		ensure("Reset MMM<> has 0 min", (zero == m1.getMin()));
+		ensure("Reset MMM<> has 0 max", (zero == m1.getMax()));
+		ensure("Reset MMM<> has 0 mean no div-by-zero", (zero == m1.getMean()));
+	}
+
+	// Testing LLSimpleStatMMM's response to large values
+	template<> template<>
+	void stat_counter_index_object_t::test<5>()
+	{
+		LLSimpleStatMMM<> m1;
+		typedef LLSimpleStatMMM<>::Value lcl_float;
+		lcl_float zero(0);
+
+		// Insert overflowing values
+		const lcl_float bignum(F32_MAX / 2);
+
+		m1.record(bignum);
+		m1.record(bignum);
+		m1.record(bignum);
+		m1.record(bignum);
+		m1.record(bignum);
+		m1.record(bignum);
+		m1.record(bignum);
+		m1.record(zero);
+
+		ensure("Overflowed MMM<> has 8 count", (8 == m1.getCount()));
+		ensure("Overflowed MMM<> has 0 min", (zero == m1.getMin()));
+		ensure("Overflowed MMM<> has huge max", (bignum == m1.getMax()));
+		ensure("Overflowed MMM<> has fetchable mean", (1.0 == m1.getMean() || true));
+		// We should be infinte but not interested in proving the IEEE standard here.
+		LLSD sd1(m1.getMean());
+		// std::cout << "Thingy:  " << m1.getMean() << " and as LLSD:  " << sd1 << std::endl;
+		ensure("Overflowed MMM<> produces LLSDable Real", (sd1.isReal()));
+	}
+
+	// Testing LLSimpleStatMMM<F32>'s external behavior
+	template<> template<>
+	void stat_counter_index_object_t::test<6>()
+	{
+		LLSimpleStatMMM<F32> m1;
+		typedef LLSimpleStatMMM<F32>::Value lcl_float;
+		lcl_float zero(0);
+
+		// Freshly-constructed
+		ensure("Constructed MMM<F32> has 0 count", (0 == m1.getCount()));
+		ensure("Constructed MMM<F32> has 0 min", (zero == m1.getMin()));
+		ensure("Constructed MMM<F32> has 0 max", (zero == m1.getMax()));
+		ensure("Constructed MMM<F32> has 0 mean no div-by-zero", (zero == m1.getMean()));
+
+		// Single insert
+		m1.record(1.0);
+		ensure("Single insert MMM<F32> has 1 count", (1 == m1.getCount()));
+		ensure("Single insert MMM<F32> has 1.0 min", (1.0 == m1.getMin()));
+		ensure("Single insert MMM<F32> has 1.0 max", (1.0 == m1.getMax()));
+		ensure("Single insert MMM<F32> has 1.0 mean", (1.0 == m1.getMean()));
+		
+		// Second insert
+		m1.record(3.0);
+		ensure("2nd insert MMM<F32> has 2 count", (2 == m1.getCount()));
+		ensure("2nd insert MMM<F32> has 1.0 min", (1.0 == m1.getMin()));
+		ensure("2nd insert MMM<F32> has 3.0 max", (3.0 == m1.getMax()));
+		ensure_approximately_equals("2nd insert MMM<F32> has 2.0 mean", m1.getMean(), lcl_float(2.0), 1);
+
+		// Third insert
+		m1.record(5.0);
+		ensure("3rd insert MMM<F32> has 3 count", (3 == m1.getCount()));
+		ensure("3rd insert MMM<F32> has 1.0 min", (1.0 == m1.getMin()));
+		ensure("3rd insert MMM<F32> has 5.0 max", (5.0 == m1.getMax()));
+		ensure_approximately_equals("3rd insert MMM<F32> has 3.0 mean", m1.getMean(), lcl_float(3.0), 1);
+
+		// Fourth insert
+		m1.record(1000000.0);
+		ensure("4th insert MMM<F32> has 4 count", (4 == m1.getCount()));
+		ensure("4th insert MMM<F32> has 1.0 min", (1.0 == m1.getMin()));
+		ensure("4th insert MMM<F32> has 1000000.0 max", (1000000.0 == m1.getMax()));
+		ensure_approximately_equals("4th insert MMM<F32> has 250002.0 mean", m1.getMean(), lcl_float(250002.0), 1);
+
+		// Reset
+		m1.reset();
+		ensure("Reset MMM<F32> has 0 count", (0 == m1.getCount()));
+		ensure("Reset MMM<F32> has 0 min", (zero == m1.getMin()));
+		ensure("Reset MMM<F32> has 0 max", (zero == m1.getMax()));
+		ensure("Reset MMM<F32> has 0 mean no div-by-zero", (zero == m1.getMean()));
+	}
+
+	// Testing LLSimpleStatMMM's response to large values
+	template<> template<>
+	void stat_counter_index_object_t::test<7>()
+	{
+		LLSimpleStatMMM<F32> m1;
+		typedef LLSimpleStatMMM<F32>::Value lcl_float;
+		lcl_float zero(0);
+
+		// Insert overflowing values
+		const lcl_float bignum(F32_MAX / 2);
+
+		m1.record(bignum);
+		m1.record(bignum);
+		m1.record(bignum);
+		m1.record(bignum);
+		m1.record(bignum);
+		m1.record(bignum);
+		m1.record(bignum);
+		m1.record(zero);
+
+		ensure("Overflowed MMM<F32> has 8 count", (8 == m1.getCount()));
+		ensure("Overflowed MMM<F32> has 0 min", (zero == m1.getMin()));
+		ensure("Overflowed MMM<F32> has huge max", (bignum == m1.getMax()));
+		ensure("Overflowed MMM<F32> has fetchable mean", (1.0 == m1.getMean() || true));
+		// We should be infinte but not interested in proving the IEEE standard here.
+		LLSD sd1(m1.getMean());
+		// std::cout << "Thingy:  " << m1.getMean() << " and as LLSD:  " << sd1 << std::endl;
+		ensure("Overflowed MMM<F32> produces LLSDable Real", (sd1.isReal()));
+	}
+
+	// Testing LLSimpleStatMMM<F64>'s external behavior
+	template<> template<>
+	void stat_counter_index_object_t::test<8>()
+	{
+		LLSimpleStatMMM<F64> m1;
+		typedef LLSimpleStatMMM<F64>::Value lcl_float;
+		lcl_float zero(0);
+
+		// Freshly-constructed
+		ensure("Constructed MMM<F64> has 0 count", (0 == m1.getCount()));
+		ensure("Constructed MMM<F64> has 0 min", (zero == m1.getMin()));
+		ensure("Constructed MMM<F64> has 0 max", (zero == m1.getMax()));
+		ensure("Constructed MMM<F64> has 0 mean no div-by-zero", (zero == m1.getMean()));
+
+		// Single insert
+		m1.record(1.0);
+		ensure("Single insert MMM<F64> has 1 count", (1 == m1.getCount()));
+		ensure("Single insert MMM<F64> has 1.0 min", (1.0 == m1.getMin()));
+		ensure("Single insert MMM<F64> has 1.0 max", (1.0 == m1.getMax()));
+		ensure("Single insert MMM<F64> has 1.0 mean", (1.0 == m1.getMean()));
+		
+		// Second insert
+		m1.record(3.0);
+		ensure("2nd insert MMM<F64> has 2 count", (2 == m1.getCount()));
+		ensure("2nd insert MMM<F64> has 1.0 min", (1.0 == m1.getMin()));
+		ensure("2nd insert MMM<F64> has 3.0 max", (3.0 == m1.getMax()));
+		ensure_approximately_equals("2nd insert MMM<F64> has 2.0 mean", m1.getMean(), lcl_float(2.0), 1);
+
+		// Third insert
+		m1.record(5.0);
+		ensure("3rd insert MMM<F64> has 3 count", (3 == m1.getCount()));
+		ensure("3rd insert MMM<F64> has 1.0 min", (1.0 == m1.getMin()));
+		ensure("3rd insert MMM<F64> has 5.0 max", (5.0 == m1.getMax()));
+		ensure_approximately_equals("3rd insert MMM<F64> has 3.0 mean", m1.getMean(), lcl_float(3.0), 1);
+
+		// Fourth insert
+		m1.record(1000000.0);
+		ensure("4th insert MMM<F64> has 4 count", (4 == m1.getCount()));
+		ensure("4th insert MMM<F64> has 1.0 min", (1.0 == m1.getMin()));
+		ensure("4th insert MMM<F64> has 1000000.0 max", (1000000.0 == m1.getMax()));
+		ensure_approximately_equals("4th insert MMM<F64> has 250002.0 mean", m1.getMean(), lcl_float(250002.0), 1);
+
+		// Reset
+		m1.reset();
+		ensure("Reset MMM<F64> has 0 count", (0 == m1.getCount()));
+		ensure("Reset MMM<F64> has 0 min", (zero == m1.getMin()));
+		ensure("Reset MMM<F64> has 0 max", (zero == m1.getMax()));
+		ensure("Reset MMM<F64> has 0 mean no div-by-zero", (zero == m1.getMean()));
+	}
+
+	// Testing LLSimpleStatMMM's response to large values
+	template<> template<>
+	void stat_counter_index_object_t::test<9>()
+	{
+		LLSimpleStatMMM<F64> m1;
+		typedef LLSimpleStatMMM<F64>::Value lcl_float;
+		lcl_float zero(0);
+
+		// Insert overflowing values
+		const lcl_float bignum(F64_MAX / 2);
+
+		m1.record(bignum);
+		m1.record(bignum);
+		m1.record(bignum);
+		m1.record(bignum);
+		m1.record(bignum);
+		m1.record(bignum);
+		m1.record(bignum);
+		m1.record(zero);
+
+		ensure("Overflowed MMM<F64> has 8 count", (8 == m1.getCount()));
+		ensure("Overflowed MMM<F64> has 0 min", (zero == m1.getMin()));
+		ensure("Overflowed MMM<F64> has huge max", (bignum == m1.getMax()));
+		ensure("Overflowed MMM<F64> has fetchable mean", (1.0 == m1.getMean() || true));
+		// We should be infinte but not interested in proving the IEEE standard here.
+		LLSD sd1(m1.getMean());
+		// std::cout << "Thingy:  " << m1.getMean() << " and as LLSD:  " << sd1 << std::endl;
+		ensure("Overflowed MMM<F64> produces LLSDable Real", (sd1.isReal()));
+	}
+
+	// Testing LLSimpleStatMMM<U64>'s external behavior
+	template<> template<>
+	void stat_counter_index_object_t::test<10>()
+	{
+		LLSimpleStatMMM<U64> m1;
+		typedef LLSimpleStatMMM<U64>::Value lcl_int;
+		lcl_int zero(0);
+
+		// Freshly-constructed
+		ensure("Constructed MMM<U64> has 0 count", (0 == m1.getCount()));
+		ensure("Constructed MMM<U64> has 0 min", (zero == m1.getMin()));
+		ensure("Constructed MMM<U64> has 0 max", (zero == m1.getMax()));
+		ensure("Constructed MMM<U64> has 0 mean no div-by-zero", (zero == m1.getMean()));
+
+		// Single insert
+		m1.record(1);
+		ensure("Single insert MMM<U64> has 1 count", (1 == m1.getCount()));
+		ensure("Single insert MMM<U64> has 1 min", (1 == m1.getMin()));
+		ensure("Single insert MMM<U64> has 1 max", (1 == m1.getMax()));
+		ensure("Single insert MMM<U64> has 1 mean", (1 == m1.getMean()));
+		
+		// Second insert
+		m1.record(3);
+		ensure("2nd insert MMM<U64> has 2 count", (2 == m1.getCount()));
+		ensure("2nd insert MMM<U64> has 1 min", (1 == m1.getMin()));
+		ensure("2nd insert MMM<U64> has 3 max", (3 == m1.getMax()));
+		ensure("2nd insert MMM<U64> has 2 mean", (2 == m1.getMean()));
+
+		// Third insert
+		m1.record(5);
+		ensure("3rd insert MMM<U64> has 3 count", (3 == m1.getCount()));
+		ensure("3rd insert MMM<U64> has 1 min", (1 == m1.getMin()));
+		ensure("3rd insert MMM<U64> has 5 max", (5 == m1.getMax()));
+		ensure("3rd insert MMM<U64> has 3 mean", (3 == m1.getMean()));
+
+		// Fourth insert
+		m1.record(U64L(1000000000000));
+		ensure("4th insert MMM<U64> has 4 count", (4 == m1.getCount()));
+		ensure("4th insert MMM<U64> has 1 min", (1 == m1.getMin()));
+		ensure("4th insert MMM<U64> has 1000000000000ULL max", (U64L(1000000000000) == m1.getMax()));
+		ensure("4th insert MMM<U64> has 250000000002ULL mean", (U64L( 250000000002) == m1.getMean()));
+
+		// Reset
+		m1.reset();
+		ensure("Reset MMM<U64> has 0 count", (0 == m1.getCount()));
+		ensure("Reset MMM<U64> has 0 min", (zero == m1.getMin()));
+		ensure("Reset MMM<U64> has 0 max", (zero == m1.getMax()));
+		ensure("Reset MMM<U64> has 0 mean no div-by-zero", (zero == m1.getMean()));
+	}
+
+	// Testing LLSimpleStatMMM's response to large values
+	template<> template<>
+	void stat_counter_index_object_t::test<11>()
+	{
+		LLSimpleStatMMM<U64> m1;
+		typedef LLSimpleStatMMM<U64>::Value lcl_int;
+		lcl_int zero(0);
+
+		// Insert overflowing values
+		const lcl_int bignum(U64L(0xffffffffffffffff) / 2);
+
+		m1.record(bignum);
+		m1.record(bignum);
+		m1.record(bignum);
+		m1.record(bignum);
+		m1.record(bignum);
+		m1.record(bignum);
+		m1.record(bignum);
+		m1.record(zero);
+
+		ensure("Overflowed MMM<U64> has 8 count", (8 == m1.getCount()));
+		ensure("Overflowed MMM<U64> has 0 min", (zero == m1.getMin()));
+		ensure("Overflowed MMM<U64> has huge max", (bignum == m1.getMax()));
+		ensure("Overflowed MMM<U64> has fetchable mean", (zero == m1.getMean() || true));
+	}
+}
-- 
cgit v1.2.3


From 20e9dbf40b0c3e4ef9674adbaca255723a412959 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Fri, 22 Oct 2010 18:37:40 -0700
Subject: EXP-273 FIXED Add button/tray for avatar picker made "toggleable"
 radio group

---
 indra/newview/app_settings/settings.xml            | 11 +++++
 indra/newview/llviewermenu.cpp                     | 51 ++++++++++------------
 indra/newview/llviewerwindow.cpp                   | 13 ++++--
 .../skins/default/xui/en/widgets/button.xml        |  2 +-
 .../skins/default/xui/en/widgets/check_box.xml     |  8 ++++
 5 files changed, 52 insertions(+), 33 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index f23b57e62c..a06e1ff384 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -586,6 +586,17 @@
       <key>Value</key>
       <integer>2</integer>
     </map>
+    <key>AvatarPickerURL</key>
+    <map>
+      <key>Comment</key>
+      <string>Avatar picker contents</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>String</string>
+      <key>Value</key>
+      <string>http://interest.secondlife.com/viewer/avatar</string>
+    </map>
     <key>AvatarBakedTextureUploadTimeout</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index ca9cc8e987..391f6b0b2a 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -844,36 +844,30 @@ class LLAdvancedCheckFeature : public view_listener_t
 }
 };
 
-void LLDestinationGuideToggle()
+void LLDestinationAndAvatarShow(const LLSD& value)
 {
-	LLView* destination_guide = gViewerWindow->getRootView()->getChildView("destination_guide_container");
-	LLView* avatar_picker = gViewerWindow->getRootView()->getChildView("avatar_picker_container");
+	S32 panel_idx = value.isDefined() ? value.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");
 
-	if ( destination_guide->getVisible() )
+	switch(panel_idx)
 	{
-		destination_guide->setVisible( FALSE );
-	}
-	else
-	{
-		LLFirstUse::notUsingDestinationGuide(false);
-		destination_guide->setVisible( true );
-		avatar_picker->setVisible( false );
-	}
-};
-
-void LLAvatarPickerToggle()
-{
-	LLView* avatar_picker = gViewerWindow->getRootView()->getChildView("avatar_picker_container");
-	LLView* destination_guide = gViewerWindow->getRootView()->getChildView("destination_guide_container");
-	if ( avatar_picker->getVisible() )
-	{
-		avatar_picker->setVisible( false );
-	}
-	else
-	{
-		LLFirstUse::notUsingAvatarPicker(false);
-		avatar_picker->setVisible( true );
-		destination_guide->setVisible( false );
+	case 0:
+		container->setVisible(true);
+		destinations->setVisible(true);
+		avatar_picker->setVisible(false);
+		break;
+	case 1:
+		container->setVisible(true);
+		destinations->setVisible(false);
+		avatar_picker->setVisible(true);
+		break;
+	default:
+		container->setVisible(false);
+		destinations->setVisible(false);
+		avatar_picker->setVisible(false);
+		break;
 	}
 };
 
@@ -8309,6 +8303,5 @@ void initialize_menus()
 
 	view_listener_t::addMenu(new LLToggleUIHints(), "ToggleUIHints");
 
-	commit.add("DestinationGuide.toggle", boost::bind(&LLDestinationGuideToggle));
-	commit.add("AvatarPicker.toggle", boost::bind(&LLAvatarPickerToggle));
+	commit.add("DestinationAndAvatar.show", boost::bind(&LLDestinationAndAvatarShow, _2));
 }
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 62e8f4223e..774cf05220 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1699,12 +1699,19 @@ void LLViewerWindow::initWorldUI()
 	buttons_panel->setFollowsAll();
 	buttons_panel_container->addChild(buttons_panel);
 
-	LLView* destination_guide = gViewerWindow->getRootView()->getChild<LLView>("destination_guide_container");
-	LLMediaCtrl* destinations = destination_guide->findChild<LLMediaCtrl>("destination_guide_contents");
+	LLView* avatar_picker_destination_guide_container = gViewerWindow->getRootView()->getChild<LLView>("avatar_picker_and_destination_guide_container");
+	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"));
+		destinations->navigateTo(gSavedSettings.getString("DestinationGuideURL"), "text/html");
 	}
+
+	if (avatar_picker)
+	{
+		avatar_picker->navigateTo(gSavedSettings.getString("AvatarPickerURL"), "text/html");
+	}
+
 }
 
 // Destroy the UI
diff --git a/indra/newview/skins/default/xui/en/widgets/button.xml b/indra/newview/skins/default/xui/en/widgets/button.xml
index 2d0a1728d5..3585a013a4 100644
--- a/indra/newview/skins/default/xui/en/widgets/button.xml
+++ b/indra/newview/skins/default/xui/en/widgets/button.xml
@@ -19,7 +19,7 @@
         image_color="ButtonImageColor"
         image_color_disabled="ButtonImageColor"
         flash_color="ButtonFlashBgColor"
-	font="SansSerifSmall"
+        font="SansSerifSmall"
         hover_glow_amount="0.15"
         halign="center"
         pad_bottom="3" 
diff --git a/indra/newview/skins/default/xui/en/widgets/check_box.xml b/indra/newview/skins/default/xui/en/widgets/check_box.xml
index 7a60bee338..cca64fad2a 100644
--- a/indra/newview/skins/default/xui/en/widgets/check_box.xml
+++ b/indra/newview/skins/default/xui/en/widgets/check_box.xml
@@ -2,9 +2,17 @@
 <check_box font="SansSerifSmall"
            follows="left|top">
   <check_box.label_text name="checkbox label"
+                        left="20"
+                        bottom="3" 
+                        width="0"
+                        height="0"
                         text_color="LabelTextColor"
                         text_readonly_color="LabelDisabledColor"/>
   <check_box.check_button name="CheckboxCtrl Button"
+                          left="2"
+                          bottom="2"
+                          width="13"
+                          height="13" 
                           commit_on_return="false"
                           label=""
                           is_toggle="true"
-- 
cgit v1.2.3


From b0d19b513de958bf5ad73278524b9deed431d166 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Mon, 25 Oct 2010 18:30:04 -0700
Subject: fixed progress bar overlapping progress bar track

---
 indra/newview/skins/default/textures/textures.xml       |   4 ++--
 .../skins/default/textures/widgets/ProgressBar.png      | Bin 220 -> 316 bytes
 2 files changed, 2 insertions(+), 2 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index 925e2b5b04..58716dcfe7 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -368,8 +368,8 @@ with the same filename but different name
   <texture name="Play_Off" file_name="icons/Play_Off.png" preload="false" />
   <texture name="Play_Over" file_name="icons/Play_Over.png" preload="false" />
   <texture name="Play_Press" file_name="icons/Play_Press.png" preload="false" />
-
-  <texture name="ProgressBar" file_name="widgets/ProgressBar.png" preload="true" scale.left="4" scale.top="10" scale.right="48" scale.bottom="2" />
+  
+  <texture name="ProgressBar" file_name="widgets/ProgressBar.png" preload="true" scale.left="4" scale.top="11" scale.right="48" scale.bottom="3" />
   <texture name="ProgressTrack" file_name="widgets/ProgressTrack.png" preload="true" scale.left="4" scale.top="13" scale.right="148" scale.bottom="2" />
 
   <texture name="PushButton_Disabled" file_name="widgets/PushButton_Disabled.png" preload="true" scale.left="4" scale.top="19" scale.right="28" scale.bottom="4" />
diff --git a/indra/newview/skins/default/textures/widgets/ProgressBar.png b/indra/newview/skins/default/textures/widgets/ProgressBar.png
index edf11ac1f5..3f0e4eba28 100644
Binary files a/indra/newview/skins/default/textures/widgets/ProgressBar.png and b/indra/newview/skins/default/textures/widgets/ProgressBar.png differ
-- 
cgit v1.2.3


From c47365480ccd6daf09c5e6f1f0672f5e0c42fadc Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Mon, 25 Oct 2010 18:33:06 -0700
Subject: EXP-322 FIXED Able spawn World map in Skylight Viewer with
 llMapDestination function

---
 indra/newview/app_settings/settings.xml | 11 +++++++++++
 indra/newview/llviewermessage.cpp       | 12 ++----------
 indra/newview/llviewermessage.h         |  1 -
 3 files changed, 13 insertions(+), 11 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index a06e1ff384..92aa6db3f8 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -8451,6 +8451,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>ScriptsCanShowUI</key>
+    <map>
+      <key>Comment</key>
+      <string>Allow LSL calls (such as LLMapDestination) to spawn viewer UI</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
     <key>SecondLifeEnterprise</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 79a3bc5776..f8e51a578a 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -5280,16 +5280,6 @@ void process_alert_core(const std::string& message, BOOL modal)
 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& first, const std::string& last, BOOL always_false)
 {
 	if (gNoRender)
@@ -6411,6 +6401,8 @@ void process_initiate_download(LLMessageSystem* msg, void**)
 
 void process_script_teleport_request(LLMessageSystem* msg, void**)
 {
+	if (!gSavedSettings.getBOOL("ScriptsCanShowUI")) return;
+
 	std::string object_name;
 	std::string sim_name;
 	LLVector3 pos;
diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h
index 6ff893f543..b4a9b8e677 100644
--- a/indra/newview/llviewermessage.h
+++ b/indra/newview/llviewermessage.h
@@ -117,7 +117,6 @@ void process_alert_core(const std::string& message, BOOL modal);
 typedef std::list<LLMeanCollisionData*> mean_collision_list_t;
 extern mean_collision_list_t gMeanCollisionList;
 
-void handle_show_mean_events(void *);
 void process_mean_collision_alert_message(LLMessageSystem* msg, void**);
 
 void process_frozen_message(LLMessageSystem* msg, void**);
-- 
cgit v1.2.3


From 4df678e33461e960cbe49bdb1cb23afe799b6cdb Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Tue, 26 Oct 2010 11:24:32 -0700
Subject: EXP-331 FIXED Avatar and Destination Guild UI Hints not showing

---
 indra/newview/llbottomtray.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp
index 1ba2a69289..5dfb9bda3c 100644
--- a/indra/newview/llbottomtray.cpp
+++ b/indra/newview/llbottomtray.cpp
@@ -520,8 +520,8 @@ void LLBottomTray::toggleCameraControls()
 BOOL LLBottomTray::postBuild()
 {
 	LLHints::registerHintTarget("bottom_tray", LLView::getHandle());
-	LLHints::registerHintTarget("dest_guide_btn", getChild<LLUICtrl>("destinations_btn")->getHandle());
-	LLHints::registerHintTarget("avatar_picker_btn", getChild<LLUICtrl>("avatar_picker_btn")->getHandle());
+	LLHints::registerHintTarget("dest_guide_btn", getChild<LLUICtrl>("destination_btn")->getHandle());
+	LLHints::registerHintTarget("avatar_picker_btn", getChild<LLUICtrl>("avatar_btn")->getHandle());
 
 	LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("NearbyChatBar.Action", boost::bind(&LLBottomTray::onContextMenuItemClicked, this, _2));
 	LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("NearbyChatBar.EnableMenuItem", boost::bind(&LLBottomTray::onContextMenuItemEnabled, this, _2));
-- 
cgit v1.2.3


From 85e1a9bf928f493587bb270cb39d9afd7e379a3a Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Tue, 26 Oct 2010 12:38:18 -0700
Subject: EXP-299 WIP Pass end-user IP and MAC from Gaikai to login.cgi

---
 indra/newview/app_settings/settings.xml | 12 ++++++++++++
 1 file changed, 12 insertions(+)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 92aa6db3f8..1d58766b37 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -3855,6 +3855,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>	
+    <key>HostID</key>
+    <map>
+      <key>Comment</key>
+      <string>Machine identifier for hosted Second Life instances</string>
+      <key>Persist</key>
+      <integer>0</integer>
+      <key>Type</key>
+      <string>String</string>
+      <key>Value</key>
+      <string />
+    </map>
     <key>HtmlHelpLastPage</key>
     <map>
       <key>Comment</key>
@@ -11983,6 +11994,7 @@
       <key>Comment</key>
       <string>Maximum texture width for user uploaded textures</string>
       <key>Persist</key>
+      <integer>1</integer>
       <key>Type</key>
       <string>S32</string>
       <key>Value</key>
-- 
cgit v1.2.3


From 67f73e5a9f124cc9a5426ed9e6d455ba65b030b5 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Tue, 26 Oct 2010 12:52:51 -0700
Subject: EXP-299 FIXED Pass end-user IP and MAC from Gaikai to login.cgi

---
 indra/newview/lllogininstance.cpp | 1 +
 1 file changed, 1 insertion(+)

(limited to 'indra/newview')

diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index 3def135fb4..05b339e173 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -183,6 +183,7 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia
 	request_params["version"] = gCurrentVersion; // Includes channel name
 	request_params["channel"] = gSavedSettings.getString("VersionChannelName");
 	request_params["id0"] = mSerialNumber;
+	request_params["host_id"] = gSavedSettings.getString("HostID");
 
 	mRequestData.clear();
 	mRequestData["method"] = "login_to_simulator";
-- 
cgit v1.2.3


From 7a74e2c0cb93be6481205a4747824fd2e7dd6640 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Tue, 26 Oct 2010 16:36:58 -0700
Subject: fix for destination guide and avatar picker hints not disappearing
 when opening destination guide/avatar picker respectively

---
 indra/newview/llviewermenu.cpp | 2 ++
 1 file changed, 2 insertions(+)

(limited to 'indra/newview')

diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 391f6b0b2a..5ad71263c3 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -857,11 +857,13 @@ void LLDestinationAndAvatarShow(const LLSD& value)
 		container->setVisible(true);
 		destinations->setVisible(true);
 		avatar_picker->setVisible(false);
+		LLFirstUse::notUsingDestinationGuide(false);
 		break;
 	case 1:
 		container->setVisible(true);
 		destinations->setVisible(false);
 		avatar_picker->setVisible(true);
+		LLFirstUse::notUsingAvatarPicker(false);
 		break;
 	default:
 		container->setVisible(false);
-- 
cgit v1.2.3


From 851f995287c0973368250b3dd8ed9a884b6a96b0 Mon Sep 17 00:00:00 2001
From: Monty Brandenberg <monty@lindenlab.com>
Date: Thu, 28 Oct 2010 08:48:26 -0700
Subject: ESC-109 Write single-thread asset stats collector for wearable.
 Code-complete with unit tests and foundation for other collectors.
 Interestingly, sim and viewer have two different ideas about asset type
 enumeration (compatible, one's just longer).  Both are missing mesh though
 that's to be expected.

---
 indra/newview/CMakeLists.txt                    |   7 +
 indra/newview/llviewerassetstats.cpp            | 277 ++++++++++++++++++++++++
 indra/newview/llviewerassetstats.h              | 143 ++++++++++++
 indra/newview/tests/llviewerassetstats_test.cpp | 167 ++++++++++++++
 4 files changed, 594 insertions(+)
 create mode 100644 indra/newview/llviewerassetstats.cpp
 create mode 100644 indra/newview/llviewerassetstats.h
 create mode 100644 indra/newview/tests/llviewerassetstats_test.cpp

(limited to 'indra/newview')

diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 0c4d2aaca6..24ef079c7e 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -476,6 +476,7 @@ set(viewer_SOURCE_FILES
     llvectorperfoptions.cpp
     llversioninfo.cpp
     llviewchildren.cpp
+    llviewerassetstats.cpp
     llviewerassetstorage.cpp
     llviewerassettype.cpp
     llviewerattachmenu.cpp
@@ -1004,6 +1005,7 @@ set(viewer_HEADER_FILES
     llvectorperfoptions.h
     llversioninfo.h
     llviewchildren.h
+    llviewerassetstats.h
     llviewerassetstorage.h
     llviewerassettype.h
     llviewerattachmenu.h
@@ -1930,6 +1932,11 @@ if (LL_TESTS)
     "${test_libs}"
     )
 
+  LL_ADD_INTEGRATION_TEST(llviewerassetstats
+	llviewerassetstats.cpp
+    "${test_libs}"
+    )
+
   #ADD_VIEWER_BUILD_TEST(llmemoryview viewer)
   #ADD_VIEWER_BUILD_TEST(llagentaccess viewer)
   #ADD_VIEWER_BUILD_TEST(llworldmap viewer)
diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp
new file mode 100644
index 0000000000..f74b394d78
--- /dev/null
+++ b/indra/newview/llviewerassetstats.cpp
@@ -0,0 +1,277 @@
+/** 
+ * @file llviewerassetstats.cpp
+ * @brief 
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ * 
+ * Copyright (c) 2010, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerassetstats.h"
+
+#include "stdtypes.h"
+
+/*
+ * References
+ *
+ * Project:
+ *   <TBD>
+ *
+ * Test Plan:
+ *   <TBD>
+ *
+ * Jiras:
+ *   <TBD>
+ *
+ * Unit Tests:
+ *   <TBD>
+ *
+ */
+
+
+// ------------------------------------------------------
+// Global data definitions
+// ------------------------------------------------------
+LLViewerAssetStats * gViewerAssetStats = NULL;
+
+
+// ------------------------------------------------------
+// Local declarations
+// ------------------------------------------------------
+namespace
+{
+
+static LLViewerAssetStats::EViewerAssetCategories
+asset_type_to_category(const LLViewerAssetType::EType at);
+
+}
+
+// ------------------------------------------------------
+// LLViewerAssetStats class definition
+// ------------------------------------------------------
+LLViewerAssetStats::LLViewerAssetStats()
+{
+	reset();
+}
+
+
+void
+LLViewerAssetStats::reset()
+{
+	for (int i = 0; i < LL_ARRAY_SIZE(mRequests); ++i)
+	{
+		mRequests[i].mEnqueued.reset();
+		mRequests[i].mDequeued.reset();
+		mRequests[i].mResponse.reset();
+	}
+}
+
+void
+LLViewerAssetStats::recordGetEnqueued(LLViewerAssetType::EType at)
+{
+	const EViewerAssetCategories eac(asset_type_to_category(at));
+	
+	++mRequests[int(eac)].mEnqueued;
+}
+	
+void
+LLViewerAssetStats::recordGetDequeued(LLViewerAssetType::EType at)
+{
+	const EViewerAssetCategories eac(asset_type_to_category(at));
+
+	++mRequests[int(eac)].mDequeued;
+}
+
+void
+LLViewerAssetStats::recordGetServiced(LLViewerAssetType::EType at, F64 duration)
+{
+	const EViewerAssetCategories eac(asset_type_to_category(at));
+
+	mRequests[int(eac)].mResponse.record(duration);
+}
+
+const LLSD
+LLViewerAssetStats::asLLSD() const
+{
+	// Top-level tags
+	static const LLSD::String tags[EVACCount] = 
+		{
+			LLSD::String("get_texture"),
+			LLSD::String("get_wearable"),
+			LLSD::String("get_sound"),
+			LLSD::String("get_gesture"),
+			LLSD::String("get_other")
+		};
+
+	// Sub-tags
+	static const LLSD::String enq_tag("enqueued");
+	static const LLSD::String deq_tag("dequeued");
+	static const LLSD::String rcnt_tag("resp_count");
+	static const LLSD::String rmin_tag("resp_min");
+	static const LLSD::String rmax_tag("resp_max");
+	static const LLSD::String rmean_tag("resp_mean");
+	
+	LLSD ret = LLSD::emptyMap();
+
+	for (int i = 0; i < EVACCount; ++i)
+	{
+		LLSD & slot = ret[tags[i]];
+		slot = LLSD::emptyMap();
+		slot[enq_tag] = LLSD(S32(mRequests[i].mEnqueued.getCount()));
+		slot[deq_tag] = LLSD(S32(mRequests[i].mDequeued.getCount()));
+		slot[rcnt_tag] = LLSD(S32(mRequests[i].mResponse.getCount()));
+		slot[rmin_tag] = LLSD(mRequests[i].mResponse.getMin());
+		slot[rmax_tag] = LLSD(mRequests[i].mResponse.getMax());
+		slot[rmean_tag] = LLSD(mRequests[i].mResponse.getMean());
+	}
+
+	return ret;
+}
+
+// ------------------------------------------------------
+// Global free-function definitions (LLViewerAssetStatsFF namespace)
+// ------------------------------------------------------
+
+namespace LLViewerAssetStatsFF
+{
+
+void
+record_enqueue(LLViewerAssetType::EType at)
+{
+	if (! gViewerAssetStats)
+		return;
+
+	gViewerAssetStats->recordGetEnqueued(at);
+}
+
+void
+record_dequeue(LLViewerAssetType::EType at)
+{
+	if (! gViewerAssetStats)
+		return;
+
+	gViewerAssetStats->recordGetDequeued(at);
+}
+
+void
+record_response(LLViewerAssetType::EType at, F64 duration)
+{
+	if (! gViewerAssetStats)
+		return;
+
+	gViewerAssetStats->recordGetServiced(at, duration);
+}
+
+} // namespace LLViewerAssetStatsFF
+
+
+// ------------------------------------------------------
+// Local function definitions
+// ------------------------------------------------------
+
+namespace
+{
+
+LLViewerAssetStats::EViewerAssetCategories
+asset_type_to_category(const LLViewerAssetType::EType at)
+{
+	// For statistical purposes, we divide GETs into several
+	// populations of asset fetches:
+	//  - textures which are de-prioritized in the asset system
+	//  - wearables (clothing, bodyparts) which directly affect
+	//    user experiences when they log in
+	//  - sounds
+	//  - gestures
+	//  - everything else.
+	//
+	llassert_always(26 == LLViewerAssetType::AT_COUNT);
+
+	// Multiple asset definitions are floating around so this requires some
+	// maintenance and attention.
+	static const LLViewerAssetStats::EViewerAssetCategories asset_to_bin_map[LLViewerAssetType::AT_COUNT] =
+		{
+			LLViewerAssetStats::EVACTextureGet,				// (0) AT_TEXTURE
+			LLViewerAssetStats::EVACSoundGet,				// AT_SOUND
+			LLViewerAssetStats::EVACOtherGet,				// AT_CALLINGCARD
+			LLViewerAssetStats::EVACOtherGet,				// AT_LANDMARK
+			LLViewerAssetStats::EVACOtherGet,				// AT_SCRIPT
+			LLViewerAssetStats::EVACWearableGet,			// AT_CLOTHING
+			LLViewerAssetStats::EVACOtherGet,				// AT_OBJECT
+			LLViewerAssetStats::EVACOtherGet,				// AT_NOTECARD
+			LLViewerAssetStats::EVACOtherGet,				// AT_CATEGORY
+			LLViewerAssetStats::EVACOtherGet,				// AT_ROOT_CATEGORY
+			LLViewerAssetStats::EVACOtherGet,				// (10) AT_LSL_TEXT
+			LLViewerAssetStats::EVACOtherGet,				// AT_LSL_BYTECODE
+			LLViewerAssetStats::EVACOtherGet,				// AT_TEXTURE_TGA
+			LLViewerAssetStats::EVACWearableGet,			// AT_BODYPART
+			LLViewerAssetStats::EVACOtherGet,				// AT_TRASH
+			LLViewerAssetStats::EVACOtherGet,				// AT_SNAPSHOT_CATEGORY
+			LLViewerAssetStats::EVACOtherGet,				// AT_LOST_AND_FOUND
+			LLViewerAssetStats::EVACSoundGet,				// AT_SOUND_WAV
+			LLViewerAssetStats::EVACOtherGet,				// AT_IMAGE_TGA
+			LLViewerAssetStats::EVACOtherGet,				// AT_IMAGE_JPEG
+			LLViewerAssetStats::EVACGestureGet,				// (20) AT_ANIMATION
+			LLViewerAssetStats::EVACGestureGet,				// AT_GESTURE
+			LLViewerAssetStats::EVACOtherGet,				// AT_SIMSTATE
+			LLViewerAssetStats::EVACOtherGet,				// AT_FAVORITE
+			LLViewerAssetStats::EVACOtherGet,				// AT_LINK
+			LLViewerAssetStats::EVACOtherGet,				// AT_LINK_FOLDER
+#if 0
+			// When LLViewerAssetType::AT_COUNT == 49
+			LLViewerAssetStats::EVACOtherGet,				// AT_FOLDER_ENSEMBLE_START
+			LLViewerAssetStats::EVACOtherGet,				// 
+			LLViewerAssetStats::EVACOtherGet,				// 
+			LLViewerAssetStats::EVACOtherGet,				// 
+			LLViewerAssetStats::EVACOtherGet,				// (30)
+			LLViewerAssetStats::EVACOtherGet,				// 
+			LLViewerAssetStats::EVACOtherGet,				// 
+			LLViewerAssetStats::EVACOtherGet,				// 
+			LLViewerAssetStats::EVACOtherGet,				// 
+			LLViewerAssetStats::EVACOtherGet,				// 
+			LLViewerAssetStats::EVACOtherGet,				// 
+			LLViewerAssetStats::EVACOtherGet,				// 
+			LLViewerAssetStats::EVACOtherGet,				// 
+			LLViewerAssetStats::EVACOtherGet,				// 
+			LLViewerAssetStats::EVACOtherGet,				// (40)
+			LLViewerAssetStats::EVACOtherGet,				// 
+			LLViewerAssetStats::EVACOtherGet,				// 
+			LLViewerAssetStats::EVACOtherGet,				// 
+			LLViewerAssetStats::EVACOtherGet,				// 
+			LLViewerAssetStats::EVACOtherGet,				// AT_FOLDER_ENSEMBLE_END
+			LLViewerAssetStats::EVACOtherGet,				// AT_CURRENT_OUTFIT
+			LLViewerAssetStats::EVACOtherGet,				// AT_OUTFIT
+			LLViewerAssetStats::EVACOtherGet				// AT_MY_OUTFITS
+#endif
+		};
+	
+	if (at < 0 || at >= LLViewerAssetType::AT_COUNT)
+	{
+		return LLViewerAssetStats::EVACOtherGet;
+	}
+	return asset_to_bin_map[at];
+}
+
+} // anonymous namespace
diff --git a/indra/newview/llviewerassetstats.h b/indra/newview/llviewerassetstats.h
new file mode 100644
index 0000000000..b56fe008e3
--- /dev/null
+++ b/indra/newview/llviewerassetstats.h
@@ -0,0 +1,143 @@
+/** 
+ * @file llviewerassetstats.h
+ * @brief Client-side collection of asset request statistics
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ * 
+ * Copyright (c) 2010, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLVIEWERASSETSTATUS_H
+#define	LL_LLVIEWERASSETSTATUS_H
+
+
+#include "linden_common.h"
+
+#include "llviewerassettype.h"
+#include "llviewerassetstorage.h"
+#include "llsimplestat.h"
+#include "llsd.h"
+
+/**
+ * @class LLViewerAssetStats
+ * @brief Records events and performance of asset put/get operations.
+ *
+ * The asset system is a combination of common code and server-
+ * and viewer-overridden derivations.  The common code is presented
+ * in here as the 'front-end' and deriviations (really the server)
+ * are presented as 'back-end'.  The distinction isn't perfect as
+ * there are legacy asset transfer systems which mostly appear
+ * as front-end stats.
+ *
+ * Statistics collected are fairly basic:
+ *  - Counts of enqueue and dequeue operations
+ *  - Counts of duplicated request fetches
+ *  - Min/Max/Mean of asset transfer operations
+ *
+ * While the stats collection interfaces appear to be fairly
+ * orthogonal across methods (GET, PUT) and asset types (texture,
+ * bodypart, etc.), the actual internal collection granularity
+ * varies greatly.  GET's operations found in the cache are
+ * treated as a single group as are duplicate requests.  Non-
+ * cached items are broken down into three groups:  textures,
+ * wearables (bodyparts, clothing) and the rest.  PUT operations
+ * are broken down into two categories:  temporary assets and
+ * non-temp.  Back-end operations do not distinguish asset types,
+ * only GET, PUT (temp) and PUT (non-temp).
+ * 
+ * No coverage for Estate Assets or Inventory Item Assets which use
+ * some different interface conventions.  It could be expanded to cover
+ * them.
+ *
+ * Access to results is by conversion to an LLSD with some standardized
+ * key names.  The intent of this structure is to be emitted as
+ * standard syslog-based metrics formatting where it can be picked
+ * up by interested parties.
+ *
+ * For convenience, a set of free functions in namespace LLAssetStatsFF
+ * are provided which operate on various counters in a way that
+ * is highly-compatible with the simulator code.
+ */
+class LLViewerAssetStats
+{
+public:
+	LLViewerAssetStats();
+	// Default destructor and assignment operator are correct.
+	
+	enum EViewerAssetCategories
+	{
+		EVACTextureGet,			//< Texture GETs
+		EVACWearableGet,		//< Wearable GETs
+		EVACSoundGet,			//< Sound GETs
+		EVACGestureGet,			//< Gesture GETs
+		EVACOtherGet,			//< Other GETs
+		
+		EVACCount				// Must be last
+	};
+	
+	void reset();
+
+	// Non-Cached GET Requests
+	void recordGetEnqueued(LLViewerAssetType::EType at);
+	void recordGetDequeued(LLViewerAssetType::EType at);
+	void recordGetServiced(LLViewerAssetType::EType at, F64 duration);
+
+	// Report Generation
+	const LLSD asLLSD() const;
+	
+protected:
+
+	struct 
+	{
+		LLSimpleStatCounter		mEnqueued;
+		LLSimpleStatCounter		mDequeued;
+		LLSimpleStatMMM<>		mResponse;
+	} mRequests [EVACCount];
+};
+
+
+/**
+ * Expectation is that the simulator and other asset-handling
+ * code will create a single instance of the stats class and
+ * make it available here.  The free functions examine this
+ * for non-zero and perform their functions conditionally.  The
+ * instance methods themselves make no assumption about this.
+ */
+extern LLViewerAssetStats * gViewerAssetStats;
+
+namespace LLViewerAssetStatsFF
+{
+
+void record_enqueue(LLViewerAssetType::EType at);
+
+void record_dequeue(LLViewerAssetType::EType at);
+
+void record_response(LLViewerAssetType::EType at, F64 duration);
+
+} // namespace LLViewerAssetStatsFF
+
+
+#endif	// LL_LLVIEWERASSETSTATUS_H
diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp
new file mode 100644
index 0000000000..5c6cc1c8c8
--- /dev/null
+++ b/indra/newview/tests/llviewerassetstats_test.cpp
@@ -0,0 +1,167 @@
+/** 
+ * @file llviewerassetstats_tut.cpp
+ * @date 2010-10-28
+ * @brief Test cases for some of newview/llviewerassetstats.cpp
+ *
+ * $LicenseInfo:firstyear=2010&license=viewergpl$
+ * 
+ * Copyright (c) 2010, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include <tut/tut.hpp>
+#include <iostream>
+
+#include "lltut.h"
+#include "../llviewerassetstats.h"
+
+static const char * all_keys[] = 
+{
+	"get_other",
+	"get_texture",
+	"get_wearable",
+	"get_sound",
+	"get_gesture"
+};
+
+static const char * resp_keys[] = 
+{
+	"get_other",
+	"get_texture",
+	"get_wearable",
+	"get_sound",
+	"get_gesture"
+};
+
+static const char * sub_keys[] =
+{
+	"dequeued",
+	"enqueued",
+	"resp_count",
+	"resp_max",
+	"resp_min",
+	"resp_mean"
+};
+
+namespace tut
+{
+	struct tst_viewerassetstats_index
+	{};
+	typedef test_group<tst_viewerassetstats_index> tst_viewerassetstats_index_t;
+	typedef tst_viewerassetstats_index_t::object tst_viewerassetstats_index_object_t;
+	tut::tst_viewerassetstats_index_t tut_tst_viewerassetstats_index("tst_viewerassetstats_test");
+
+	// Testing free functions without global stats allocated
+	template<> template<>
+	void tst_viewerassetstats_index_object_t::test<1>()
+	{
+		// Check that helpers aren't bothered by missing global stats
+		ensure("Global gViewerAssetStats should be NULL", (NULL == gViewerAssetStats));
+
+		LLViewerAssetStatsFF::record_enqueue(LLViewerAssetType::AT_TEXTURE);
+
+		LLViewerAssetStatsFF::record_dequeue(LLViewerAssetType::AT_TEXTURE);
+
+		LLViewerAssetStatsFF::record_response(LLViewerAssetType::AT_GESTURE, 12.3);
+	}
+
+	// Create a non-global instance and check the structure
+	template<> template<>
+	void tst_viewerassetstats_index_object_t::test<2>()
+	{
+		ensure("Global gViewerAssetStats should be NULL", (NULL == gViewerAssetStats));
+
+		LLViewerAssetStats * it = new LLViewerAssetStats();
+
+		ensure("Global gViewerAssetStats should still be NULL", (NULL == gViewerAssetStats));
+		
+		LLSD sd = it->asLLSD();
+		
+		delete it;
+
+		// Check the structure of the LLSD
+		for (int i = 0; i < LL_ARRAY_SIZE(all_keys); ++i)
+		{
+			std::string line = llformat("Has '%s' key", all_keys[i]);
+			ensure(line, sd.has(all_keys[i]));
+		}
+
+		for (int i = 0; i < LL_ARRAY_SIZE(resp_keys); ++i)
+		{
+			for (int j = 0; j < LL_ARRAY_SIZE(sub_keys); ++j)
+			{
+				std::string line = llformat("Key '%s' has '%s' key", resp_keys[i], sub_keys[j]);
+				ensure(line, sd[resp_keys[i]].has(sub_keys[j]));
+			}
+		}
+	}
+
+	// Create a non-global instance and check some content
+	template<> template<>
+	void tst_viewerassetstats_index_object_t::test<3>()
+	{
+		LLViewerAssetStats * it = new LLViewerAssetStats();
+		
+		LLSD sd = it->asLLSD();
+		
+		delete it;
+
+		// Check a few points on the tree for content
+		ensure("sd[get_texture][dequeued] is 0", (0 == sd["get_texture"]["dequeued"].asInteger()));
+		ensure("sd[get_sound][resp_min] is 0", (0.0 == sd["get_sound"]["resp_min"].asReal()));
+	}
+
+	// Create a global instance and verify free functions do something useful
+	template<> template<>
+	void tst_viewerassetstats_index_object_t::test<4>()
+	{
+		gViewerAssetStats = new LLViewerAssetStats();
+
+		LLViewerAssetStatsFF::record_enqueue(LLViewerAssetType::AT_TEXTURE);
+		LLViewerAssetStatsFF::record_dequeue(LLViewerAssetType::AT_TEXTURE);
+
+		LLViewerAssetStatsFF::record_enqueue(LLViewerAssetType::AT_BODYPART);
+		LLViewerAssetStatsFF::record_dequeue(LLViewerAssetType::AT_BODYPART);
+
+		LLSD sd = gViewerAssetStats->asLLSD();
+		
+		// Check a few points on the tree for content
+		ensure("sd[get_texture][enqueued] is 1", (1 == sd["get_texture"]["enqueued"].asInteger()));
+		ensure("sd[get_gesture][dequeued] is 0", (0 == sd["get_gesture"]["dequeued"].asInteger()));
+
+		// Reset and check zeros...
+		gViewerAssetStats->reset();
+		sd = gViewerAssetStats->asLLSD();
+		
+		delete gViewerAssetStats;
+		gViewerAssetStats = NULL;
+
+		ensure("sd[get_texture][enqueued] is reset", (0 == sd["get_texture"]["enqueued"].asInteger()));
+		ensure("sd[get_gesture][dequeued] is reset", (0 == sd["get_gesture"]["dequeued"].asInteger()));
+	}
+
+}
-- 
cgit v1.2.3


From 1ed9d997a6c380f71f2da182c8083321e35b5034 Mon Sep 17 00:00:00 2001
From: Monty Brandenberg <monty@lindenlab.com>
Date: Fri, 29 Oct 2010 08:50:03 -0700
Subject: ESC-111 Texture interfaces Mainly expand the categories to include
 protocol and location/temp nature of texture asset.

---
 indra/newview/llviewerassetstats.cpp            | 157 ++++++++++++++----------
 indra/newview/llviewerassetstats.h              |  27 ++--
 indra/newview/tests/llviewerassetstats_test.cpp |  51 ++++----
 3 files changed, 134 insertions(+), 101 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp
index f74b394d78..0852573bbd 100644
--- a/indra/newview/llviewerassetstats.cpp
+++ b/indra/newview/llviewerassetstats.cpp
@@ -65,7 +65,7 @@ namespace
 {
 
 static LLViewerAssetStats::EViewerAssetCategories
-asset_type_to_category(const LLViewerAssetType::EType at);
+asset_type_to_category(const LLViewerAssetType::EType at, bool with_http, bool is_temp);
 
 }
 
@@ -90,25 +90,25 @@ LLViewerAssetStats::reset()
 }
 
 void
-LLViewerAssetStats::recordGetEnqueued(LLViewerAssetType::EType at)
+LLViewerAssetStats::recordGetEnqueued(LLViewerAssetType::EType at, bool with_http, bool is_temp)
 {
-	const EViewerAssetCategories eac(asset_type_to_category(at));
+	const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp));
 	
 	++mRequests[int(eac)].mEnqueued;
 }
 	
 void
-LLViewerAssetStats::recordGetDequeued(LLViewerAssetType::EType at)
+LLViewerAssetStats::recordGetDequeued(LLViewerAssetType::EType at, bool with_http, bool is_temp)
 {
-	const EViewerAssetCategories eac(asset_type_to_category(at));
+	const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp));
 
 	++mRequests[int(eac)].mDequeued;
 }
 
 void
-LLViewerAssetStats::recordGetServiced(LLViewerAssetType::EType at, F64 duration)
+LLViewerAssetStats::recordGetServiced(LLViewerAssetType::EType at, bool with_http, bool is_temp, F64 duration)
 {
-	const EViewerAssetCategories eac(asset_type_to_category(at));
+	const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp));
 
 	mRequests[int(eac)].mResponse.record(duration);
 }
@@ -119,10 +119,13 @@ LLViewerAssetStats::asLLSD() const
 	// Top-level tags
 	static const LLSD::String tags[EVACCount] = 
 		{
-			LLSD::String("get_texture"),
-			LLSD::String("get_wearable"),
-			LLSD::String("get_sound"),
-			LLSD::String("get_gesture"),
+			LLSD::String("get_texture_temp_http"),
+			LLSD::String("get_texture_temp_udp"),
+			LLSD::String("get_texture_non_temp_http"),
+			LLSD::String("get_texture_non_temp_udp"),
+			LLSD::String("get_wearable_udp"),
+			LLSD::String("get_sound_udp"),
+			LLSD::String("get_gesture_udp"),
 			LLSD::String("get_other")
 		};
 
@@ -159,30 +162,30 @@ namespace LLViewerAssetStatsFF
 {
 
 void
-record_enqueue(LLViewerAssetType::EType at)
+record_enqueue(LLViewerAssetType::EType at, bool with_http, bool is_temp)
 {
 	if (! gViewerAssetStats)
 		return;
 
-	gViewerAssetStats->recordGetEnqueued(at);
+	gViewerAssetStats->recordGetEnqueued(at, with_http, is_temp);
 }
 
 void
-record_dequeue(LLViewerAssetType::EType at)
+record_dequeue(LLViewerAssetType::EType at, bool with_http, bool is_temp)
 {
 	if (! gViewerAssetStats)
 		return;
 
-	gViewerAssetStats->recordGetDequeued(at);
+	gViewerAssetStats->recordGetDequeued(at, with_http, is_temp);
 }
 
 void
-record_response(LLViewerAssetType::EType at, F64 duration)
+record_response(LLViewerAssetType::EType at, bool with_http, bool is_temp, F64 duration)
 {
 	if (! gViewerAssetStats)
 		return;
 
-	gViewerAssetStats->recordGetServiced(at, duration);
+	gViewerAssetStats->recordGetServiced(at, with_http, is_temp, duration);
 }
 
 } // namespace LLViewerAssetStatsFF
@@ -196,7 +199,7 @@ namespace
 {
 
 LLViewerAssetStats::EViewerAssetCategories
-asset_type_to_category(const LLViewerAssetType::EType at)
+asset_type_to_category(const LLViewerAssetType::EType at, bool with_http, bool is_temp)
 {
 	// For statistical purposes, we divide GETs into several
 	// populations of asset fetches:
@@ -213,57 +216,57 @@ asset_type_to_category(const LLViewerAssetType::EType at)
 	// maintenance and attention.
 	static const LLViewerAssetStats::EViewerAssetCategories asset_to_bin_map[LLViewerAssetType::AT_COUNT] =
 		{
-			LLViewerAssetStats::EVACTextureGet,				// (0) AT_TEXTURE
-			LLViewerAssetStats::EVACSoundGet,				// AT_SOUND
-			LLViewerAssetStats::EVACOtherGet,				// AT_CALLINGCARD
-			LLViewerAssetStats::EVACOtherGet,				// AT_LANDMARK
-			LLViewerAssetStats::EVACOtherGet,				// AT_SCRIPT
-			LLViewerAssetStats::EVACWearableGet,			// AT_CLOTHING
-			LLViewerAssetStats::EVACOtherGet,				// AT_OBJECT
-			LLViewerAssetStats::EVACOtherGet,				// AT_NOTECARD
-			LLViewerAssetStats::EVACOtherGet,				// AT_CATEGORY
-			LLViewerAssetStats::EVACOtherGet,				// AT_ROOT_CATEGORY
-			LLViewerAssetStats::EVACOtherGet,				// (10) AT_LSL_TEXT
-			LLViewerAssetStats::EVACOtherGet,				// AT_LSL_BYTECODE
-			LLViewerAssetStats::EVACOtherGet,				// AT_TEXTURE_TGA
-			LLViewerAssetStats::EVACWearableGet,			// AT_BODYPART
-			LLViewerAssetStats::EVACOtherGet,				// AT_TRASH
-			LLViewerAssetStats::EVACOtherGet,				// AT_SNAPSHOT_CATEGORY
-			LLViewerAssetStats::EVACOtherGet,				// AT_LOST_AND_FOUND
-			LLViewerAssetStats::EVACSoundGet,				// AT_SOUND_WAV
-			LLViewerAssetStats::EVACOtherGet,				// AT_IMAGE_TGA
-			LLViewerAssetStats::EVACOtherGet,				// AT_IMAGE_JPEG
-			LLViewerAssetStats::EVACGestureGet,				// (20) AT_ANIMATION
-			LLViewerAssetStats::EVACGestureGet,				// AT_GESTURE
-			LLViewerAssetStats::EVACOtherGet,				// AT_SIMSTATE
-			LLViewerAssetStats::EVACOtherGet,				// AT_FAVORITE
-			LLViewerAssetStats::EVACOtherGet,				// AT_LINK
-			LLViewerAssetStats::EVACOtherGet,				// AT_LINK_FOLDER
+			LLViewerAssetStats::EVACTextureTempHTTPGet,			// (0) AT_TEXTURE
+			LLViewerAssetStats::EVACSoundUDPGet,				// AT_SOUND
+			LLViewerAssetStats::EVACOtherGet,					// AT_CALLINGCARD
+			LLViewerAssetStats::EVACOtherGet,					// AT_LANDMARK
+			LLViewerAssetStats::EVACOtherGet,					// AT_SCRIPT
+			LLViewerAssetStats::EVACWearableUDPGet,				// AT_CLOTHING
+			LLViewerAssetStats::EVACOtherGet,					// AT_OBJECT
+			LLViewerAssetStats::EVACOtherGet,					// AT_NOTECARD
+			LLViewerAssetStats::EVACOtherGet,					// AT_CATEGORY
+			LLViewerAssetStats::EVACOtherGet,					// AT_ROOT_CATEGORY
+			LLViewerAssetStats::EVACOtherGet,					// (10) AT_LSL_TEXT
+			LLViewerAssetStats::EVACOtherGet,					// AT_LSL_BYTECODE
+			LLViewerAssetStats::EVACOtherGet,					// AT_TEXTURE_TGA
+			LLViewerAssetStats::EVACWearableUDPGet,				// AT_BODYPART
+			LLViewerAssetStats::EVACOtherGet,					// AT_TRASH
+			LLViewerAssetStats::EVACOtherGet,					// AT_SNAPSHOT_CATEGORY
+			LLViewerAssetStats::EVACOtherGet,					// AT_LOST_AND_FOUND
+			LLViewerAssetStats::EVACSoundUDPGet,				// AT_SOUND_WAV
+			LLViewerAssetStats::EVACOtherGet,					// AT_IMAGE_TGA
+			LLViewerAssetStats::EVACOtherGet,					// AT_IMAGE_JPEG
+			LLViewerAssetStats::EVACGestureUDPGet,				// (20) AT_ANIMATION
+			LLViewerAssetStats::EVACGestureUDPGet,				// AT_GESTURE
+			LLViewerAssetStats::EVACOtherGet,					// AT_SIMSTATE
+			LLViewerAssetStats::EVACOtherGet,					// AT_FAVORITE
+			LLViewerAssetStats::EVACOtherGet,					// AT_LINK
+			LLViewerAssetStats::EVACOtherGet,					// AT_LINK_FOLDER
 #if 0
 			// When LLViewerAssetType::AT_COUNT == 49
-			LLViewerAssetStats::EVACOtherGet,				// AT_FOLDER_ENSEMBLE_START
-			LLViewerAssetStats::EVACOtherGet,				// 
-			LLViewerAssetStats::EVACOtherGet,				// 
-			LLViewerAssetStats::EVACOtherGet,				// 
-			LLViewerAssetStats::EVACOtherGet,				// (30)
-			LLViewerAssetStats::EVACOtherGet,				// 
-			LLViewerAssetStats::EVACOtherGet,				// 
-			LLViewerAssetStats::EVACOtherGet,				// 
-			LLViewerAssetStats::EVACOtherGet,				// 
-			LLViewerAssetStats::EVACOtherGet,				// 
-			LLViewerAssetStats::EVACOtherGet,				// 
-			LLViewerAssetStats::EVACOtherGet,				// 
-			LLViewerAssetStats::EVACOtherGet,				// 
-			LLViewerAssetStats::EVACOtherGet,				// 
-			LLViewerAssetStats::EVACOtherGet,				// (40)
-			LLViewerAssetStats::EVACOtherGet,				// 
-			LLViewerAssetStats::EVACOtherGet,				// 
-			LLViewerAssetStats::EVACOtherGet,				// 
-			LLViewerAssetStats::EVACOtherGet,				// 
-			LLViewerAssetStats::EVACOtherGet,				// AT_FOLDER_ENSEMBLE_END
-			LLViewerAssetStats::EVACOtherGet,				// AT_CURRENT_OUTFIT
-			LLViewerAssetStats::EVACOtherGet,				// AT_OUTFIT
-			LLViewerAssetStats::EVACOtherGet				// AT_MY_OUTFITS
+			LLViewerAssetStats::EVACOtherGet,					// AT_FOLDER_ENSEMBLE_START
+			LLViewerAssetStats::EVACOtherGet,					// 
+			LLViewerAssetStats::EVACOtherGet,					// 
+			LLViewerAssetStats::EVACOtherGet,					// 
+			LLViewerAssetStats::EVACOtherGet,					// (30)
+			LLViewerAssetStats::EVACOtherGet,					// 
+			LLViewerAssetStats::EVACOtherGet,					// 
+			LLViewerAssetStats::EVACOtherGet,					// 
+			LLViewerAssetStats::EVACOtherGet,					// 
+			LLViewerAssetStats::EVACOtherGet,					// 
+			LLViewerAssetStats::EVACOtherGet,					// 
+			LLViewerAssetStats::EVACOtherGet,					// 
+			LLViewerAssetStats::EVACOtherGet,					// 
+			LLViewerAssetStats::EVACOtherGet,					// 
+			LLViewerAssetStats::EVACOtherGet,					// (40)
+			LLViewerAssetStats::EVACOtherGet,					// 
+			LLViewerAssetStats::EVACOtherGet,					// 
+			LLViewerAssetStats::EVACOtherGet,					// 
+			LLViewerAssetStats::EVACOtherGet,					// 
+			LLViewerAssetStats::EVACOtherGet,					// AT_FOLDER_ENSEMBLE_END
+			LLViewerAssetStats::EVACOtherGet,					// AT_CURRENT_OUTFIT
+			LLViewerAssetStats::EVACOtherGet,					// AT_OUTFIT
+			LLViewerAssetStats::EVACOtherGet					// AT_MY_OUTFITS
 #endif
 		};
 	
@@ -271,7 +274,25 @@ asset_type_to_category(const LLViewerAssetType::EType at)
 	{
 		return LLViewerAssetStats::EVACOtherGet;
 	}
-	return asset_to_bin_map[at];
+	LLViewerAssetStats::EViewerAssetCategories ret(asset_to_bin_map[at]);
+	if (LLViewerAssetStats::EVACTextureTempHTTPGet == ret)
+	{
+		// Indexed with [is_temp][with_http]
+		static const LLViewerAssetStats::EViewerAssetCategories texture_bin_map[2][2] =
+			{
+				{
+					LLViewerAssetStats::EVACTextureNonTempUDPGet,
+					LLViewerAssetStats::EVACTextureNonTempHTTPGet,
+				},
+				{
+					LLViewerAssetStats::EVACTextureTempUDPGet,
+					LLViewerAssetStats::EVACTextureTempHTTPGet,
+				}
+			};
+
+		ret = texture_bin_map[is_temp][with_http];
+	}
+	return ret;
 }
 
 } // anonymous namespace
diff --git a/indra/newview/llviewerassetstats.h b/indra/newview/llviewerassetstats.h
index b56fe008e3..9d66a1e89b 100644
--- a/indra/newview/llviewerassetstats.h
+++ b/indra/newview/llviewerassetstats.h
@@ -89,21 +89,24 @@ public:
 	
 	enum EViewerAssetCategories
 	{
-		EVACTextureGet,			//< Texture GETs
-		EVACWearableGet,		//< Wearable GETs
-		EVACSoundGet,			//< Sound GETs
-		EVACGestureGet,			//< Gesture GETs
-		EVACOtherGet,			//< Other GETs
+		EVACTextureTempHTTPGet,			//< Texture GETs
+		EVACTextureTempUDPGet,			//< Texture GETs
+		EVACTextureNonTempHTTPGet,		//< Texture GETs
+		EVACTextureNonTempUDPGet,		//< Texture GETs
+		EVACWearableUDPGet,				//< Wearable GETs
+		EVACSoundUDPGet,				//< Sound GETs
+		EVACGestureUDPGet,				//< Gesture GETs
+		EVACOtherGet,					//< Other GETs
 		
-		EVACCount				// Must be last
+		EVACCount						// Must be last
 	};
 	
 	void reset();
 
 	// Non-Cached GET Requests
-	void recordGetEnqueued(LLViewerAssetType::EType at);
-	void recordGetDequeued(LLViewerAssetType::EType at);
-	void recordGetServiced(LLViewerAssetType::EType at, F64 duration);
+	void recordGetEnqueued(LLViewerAssetType::EType at, bool with_http, bool is_temp);
+	void recordGetDequeued(LLViewerAssetType::EType at, bool with_http, bool is_temp);
+	void recordGetServiced(LLViewerAssetType::EType at, bool with_http, bool is_temp, F64 duration);
 
 	// Report Generation
 	const LLSD asLLSD() const;
@@ -131,11 +134,11 @@ extern LLViewerAssetStats * gViewerAssetStats;
 namespace LLViewerAssetStatsFF
 {
 
-void record_enqueue(LLViewerAssetType::EType at);
+void record_enqueue(LLViewerAssetType::EType at, bool with_http, bool is_temp);
 
-void record_dequeue(LLViewerAssetType::EType at);
+void record_dequeue(LLViewerAssetType::EType at, bool with_http, bool is_temp);
 
-void record_response(LLViewerAssetType::EType at, F64 duration);
+void record_response(LLViewerAssetType::EType at, bool with_http, bool is_temp, F64 duration);
 
 } // namespace LLViewerAssetStatsFF
 
diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp
index 5c6cc1c8c8..50d348c7e3 100644
--- a/indra/newview/tests/llviewerassetstats_test.cpp
+++ b/indra/newview/tests/llviewerassetstats_test.cpp
@@ -42,19 +42,25 @@
 static const char * all_keys[] = 
 {
 	"get_other",
-	"get_texture",
-	"get_wearable",
-	"get_sound",
-	"get_gesture"
+	"get_texture_temp_http",
+	"get_texture_temp_udp",
+	"get_texture_non_temp_http",
+	"get_texture_non_temp_udp",
+	"get_wearable_udp",
+	"get_sound_udp",
+	"get_gesture_udp"
 };
 
 static const char * resp_keys[] = 
 {
 	"get_other",
-	"get_texture",
-	"get_wearable",
-	"get_sound",
-	"get_gesture"
+	"get_texture_temp_http",
+	"get_texture_temp_udp",
+	"get_texture_non_temp_http",
+	"get_texture_non_temp_udp",
+	"get_wearable_udp",
+	"get_sound_udp",
+	"get_gesture_udp"
 };
 
 static const char * sub_keys[] =
@@ -82,11 +88,11 @@ namespace tut
 		// Check that helpers aren't bothered by missing global stats
 		ensure("Global gViewerAssetStats should be NULL", (NULL == gViewerAssetStats));
 
-		LLViewerAssetStatsFF::record_enqueue(LLViewerAssetType::AT_TEXTURE);
+		LLViewerAssetStatsFF::record_enqueue(LLViewerAssetType::AT_TEXTURE, false, false);
 
-		LLViewerAssetStatsFF::record_dequeue(LLViewerAssetType::AT_TEXTURE);
+		LLViewerAssetStatsFF::record_dequeue(LLViewerAssetType::AT_TEXTURE, false, false);
 
-		LLViewerAssetStatsFF::record_response(LLViewerAssetType::AT_GESTURE, 12.3);
+		LLViewerAssetStatsFF::record_response(LLViewerAssetType::AT_GESTURE, false, false, 12.3);
 	}
 
 	// Create a non-global instance and check the structure
@@ -131,8 +137,8 @@ namespace tut
 		delete it;
 
 		// Check a few points on the tree for content
-		ensure("sd[get_texture][dequeued] is 0", (0 == sd["get_texture"]["dequeued"].asInteger()));
-		ensure("sd[get_sound][resp_min] is 0", (0.0 == sd["get_sound"]["resp_min"].asReal()));
+		ensure("sd[get_texture_temp_http][dequeued] is 0", (0 == sd["get_texture_temp_http"]["dequeued"].asInteger()));
+		ensure("sd[get_sound_udp][resp_min] is 0", (0.0 == sd["get_sound_udp"]["resp_min"].asReal()));
 	}
 
 	// Create a global instance and verify free functions do something useful
@@ -141,17 +147,20 @@ namespace tut
 	{
 		gViewerAssetStats = new LLViewerAssetStats();
 
-		LLViewerAssetStatsFF::record_enqueue(LLViewerAssetType::AT_TEXTURE);
-		LLViewerAssetStatsFF::record_dequeue(LLViewerAssetType::AT_TEXTURE);
+		LLViewerAssetStatsFF::record_enqueue(LLViewerAssetType::AT_TEXTURE, false, false);
+		LLViewerAssetStatsFF::record_dequeue(LLViewerAssetType::AT_TEXTURE, false, false);
 
-		LLViewerAssetStatsFF::record_enqueue(LLViewerAssetType::AT_BODYPART);
-		LLViewerAssetStatsFF::record_dequeue(LLViewerAssetType::AT_BODYPART);
+		LLViewerAssetStatsFF::record_enqueue(LLViewerAssetType::AT_BODYPART, false, false);
+		LLViewerAssetStatsFF::record_dequeue(LLViewerAssetType::AT_BODYPART, false, false);
 
 		LLSD sd = gViewerAssetStats->asLLSD();
 		
 		// Check a few points on the tree for content
-		ensure("sd[get_texture][enqueued] is 1", (1 == sd["get_texture"]["enqueued"].asInteger()));
-		ensure("sd[get_gesture][dequeued] is 0", (0 == sd["get_gesture"]["dequeued"].asInteger()));
+		ensure("sd[get_texture_non_temp_udp][enqueued] is 1", (1 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger()));
+		ensure("sd[get_texture_temp_udp][enqueued] is 0", (0 == sd["get_texture_temp_udp"]["enqueued"].asInteger()));
+		ensure("sd[get_texture_non_temp_http][enqueued] is 0", (0 == sd["get_texture_non_temp_http"]["enqueued"].asInteger()));
+		ensure("sd[get_texture_temp_http][enqueued] is 0", (0 == sd["get_texture_temp_http"]["enqueued"].asInteger()));
+		ensure("sd[get_gesture_udp][dequeued] is 0", (0 == sd["get_gesture_udp"]["dequeued"].asInteger()));
 
 		// Reset and check zeros...
 		gViewerAssetStats->reset();
@@ -160,8 +169,8 @@ namespace tut
 		delete gViewerAssetStats;
 		gViewerAssetStats = NULL;
 
-		ensure("sd[get_texture][enqueued] is reset", (0 == sd["get_texture"]["enqueued"].asInteger()));
-		ensure("sd[get_gesture][dequeued] is reset", (0 == sd["get_gesture"]["dequeued"].asInteger()));
+		ensure("sd[get_texture_non_temp_udp][enqueued] is reset", (0 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger()));
+		ensure("sd[get_gesture_udp][dequeued] is reset", (0 == sd["get_gesture_udp"]["dequeued"].asInteger()));
 	}
 
 }
-- 
cgit v1.2.3


From de11ebefe905f011b4e8f38f8f9ed8832bdb87e8 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Fri, 29 Oct 2010 16:50:09 -0700
Subject: EXP-359 WIP Disable MOAP fixed AudioStreamingMusic and
 AudioStreamingMedia so they are independent this way we can keep audio on but
 disable html content

---
 indra/newview/llviewerparcelmgr.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp
index 3c9e351ca1..a2f6f67b4d 100644
--- a/indra/newview/llviewerparcelmgr.cpp
+++ b/indra/newview/llviewerparcelmgr.cpp
@@ -1784,8 +1784,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use
 
 void optionally_start_music(const std::string& music_url)
 {
-	if (gSavedSettings.getBOOL("AudioStreamingMusic") &&
-	    gSavedSettings.getBOOL("AudioStreamingMedia"))
+	if (gSavedSettings.getBOOL("AudioStreamingMusic"))
 	{
 		// only play music when you enter a new parcel if the UI control for this
 		// was not *explicitly* stopped by the user. (part of SL-4878)
-- 
cgit v1.2.3


From 38a182f62fcdd3c8e684459bf29a434bf36dbce2 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Mon, 1 Nov 2010 13:45:55 -0700
Subject: EXP-371 Chat/IM bubble notifications not aligned with bottom bar

---
 indra/newview/llscreenchannel.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp
index b90ff80294..5a36393f28 100644
--- a/indra/newview/llscreenchannel.cpp
+++ b/indra/newview/llscreenchannel.cpp
@@ -145,7 +145,7 @@ void LLScreenChannelBase::init(S32 channel_left, S32 channel_right)
 void	LLScreenChannelBase::updateBottom()
 {
 	S32 channel_top = gViewerWindow->getWorldViewRectScaled().getHeight();
-	S32 channel_bottom = gViewerWindow->getWorldViewRectScaled().mBottom + gSavedSettings.getS32("ChannelBottomPanelMargin");
+	S32 channel_bottom = gSavedSettings.getS32("ChannelBottomPanelMargin");
 	S32 channel_left = getRect().mLeft;
 	S32 channel_right = getRect().mRight;
 	setRect(LLRect(channel_left, channel_top, channel_right, channel_bottom));
-- 
cgit v1.2.3


From f1830e905c553bff42a9035bc4bee9c40d707617 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Mon, 1 Nov 2010 16:29:49 -0700
Subject: removed extra space that resulted in strange line wrapping

---
 indra/newview/skins/default/xui/en/notifications.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index b32a33b59a..5a609e201d 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -6452,7 +6452,7 @@ Mute everyone?
   label="Change your Look"
   type="hint"
   unique="true">
-    Would you like to try a new look?  Click the button below to see more Avatars.
+    Would you like to try a new look? Click the button below to see more Avatars.
   </notification>
 
   <notification
-- 
cgit v1.2.3


From 5085fbfbdda90c396f1eb52b2a27212531ac87bc Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Tue, 2 Nov 2010 16:57:55 -0700
Subject: made focus_on_click a param for LLMediaCtrl

---
 indra/newview/llmediactrl.cpp | 13 +++----------
 indra/newview/llmediactrl.h   |  3 ++-
 2 files changed, 5 insertions(+), 11 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp
index e84c9152b1..0f66713ab0 100644
--- a/indra/newview/llmediactrl.cpp
+++ b/indra/newview/llmediactrl.cpp
@@ -70,7 +70,8 @@ LLMediaCtrl::Params::Params()
 	caret_color("caret_color"),
 	initial_mime_type("initial_mime_type"),
 	media_id("media_id"),
-	trusted_content("trusted_content", false)
+	trusted_content("trusted_content", false),
+	focus_on_click("focus_on_click", true)
 {
 	tab_stop(false);
 }
@@ -86,7 +87,7 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :
 	mIgnoreUIScale( true ),
 	mAlwaysRefresh( false ),
 	mMediaSource( 0 ),
-	mTakeFocusOnClick( true ),
+	mTakeFocusOnClick( p.focus_on_click ),
 	mCurrentNavUrl( "" ),
 	mStretchToFill( true ),
 	mMaintainAspectRatio ( true ),
@@ -206,14 +207,6 @@ BOOL LLMediaCtrl::handleMouseUp( S32 x, S32 y, MASK mask )
 	if (mMediaSource)
 	{
 		mMediaSource->mouseUp(x, y, mask);
-
-		// *HACK: LLMediaImplLLMozLib automatically takes focus on mouseup,
-		// in addition to the onFocusReceived() call below.  Undo this. JC
-		if (!mTakeFocusOnClick)
-		{
-			mMediaSource->focus(false);
-			gViewerWindow->focusClient();
-		}
 	}
 	
 	gFocusMgr.setMouseCapture( NULL );
diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h
index 65dfbbff78..96bb0c1df5 100644
--- a/indra/newview/llmediactrl.h
+++ b/indra/newview/llmediactrl.h
@@ -53,7 +53,8 @@ public:
 								ignore_ui_scale,
 								hide_loading,
 								decouple_texture_size,
-								trusted_content;
+								trusted_content,
+								focus_on_click;
 								
 		Optional<S32>			texture_width,
 								texture_height;
-- 
cgit v1.2.3


From 4bdac3f152862b257b9babe9b5a43329c9f544f9 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Thu, 4 Nov 2010 11:37:41 -0700
Subject: fixed hotspots on one-click action cursors

---
 indra/newview/res/toolbuy.cur  | Bin 4286 -> 4286 bytes
 indra/newview/res/toolopen.cur | Bin 4286 -> 4286 bytes
 indra/newview/res/toolsit.cur  | Bin 4286 -> 4286 bytes
 3 files changed, 0 insertions(+), 0 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/res/toolbuy.cur b/indra/newview/res/toolbuy.cur
index a1bc278116..65bbf01d45 100644
Binary files a/indra/newview/res/toolbuy.cur and b/indra/newview/res/toolbuy.cur differ
diff --git a/indra/newview/res/toolopen.cur b/indra/newview/res/toolopen.cur
index a72cdfe4c0..22ecbd5228 100644
Binary files a/indra/newview/res/toolopen.cur and b/indra/newview/res/toolopen.cur differ
diff --git a/indra/newview/res/toolsit.cur b/indra/newview/res/toolsit.cur
index 6327bdb281..d26b6f8638 100644
Binary files a/indra/newview/res/toolsit.cur and b/indra/newview/res/toolsit.cur differ
-- 
cgit v1.2.3


From fd2d4dc1b16430edd367a8b0f4162238bbb7e22c Mon Sep 17 00:00:00 2001
From: Monty Brandenberg <monty@lindenlab.com>
Date: Wed, 10 Nov 2010 08:44:53 -0800
Subject: ESC-110 ESC-111 Cleanup passes on the two threaded collectors with
 better comments and more complete unit tests.

---
 indra/newview/llviewerassetstats.cpp            | 172 +++++++++++---
 indra/newview/llviewerassetstats.h              | 152 ++++++++----
 indra/newview/tests/llviewerassetstats_test.cpp | 303 ++++++++++++++++++++++--
 3 files changed, 533 insertions(+), 94 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp
index 0852573bbd..a6c4685bf1 100644
--- a/indra/newview/llviewerassetstats.cpp
+++ b/indra/newview/llviewerassetstats.cpp
@@ -47,7 +47,7 @@
  *   <TBD>
  *
  * Unit Tests:
- *   <TBD>
+ *   indra/newview/tests/llviewerassetstats_test.cpp
  *
  */
 
@@ -55,7 +55,8 @@
 // ------------------------------------------------------
 // Global data definitions
 // ------------------------------------------------------
-LLViewerAssetStats * gViewerAssetStats = NULL;
+LLViewerAssetStats * gViewerAssetStatsMain(0);
+LLViewerAssetStats * gViewerAssetStatsThread1(0);
 
 
 // ------------------------------------------------------
@@ -69,6 +70,21 @@ asset_type_to_category(const LLViewerAssetType::EType at, bool with_http, bool i
 
 }
 
+// ------------------------------------------------------
+// LLViewerAssetStats::PerRegionStats struct definition
+// ------------------------------------------------------
+void
+LLViewerAssetStats::PerRegionStats::reset()
+{
+	for (int i(0); i < LL_ARRAY_SIZE(mRequests); ++i)
+	{
+		mRequests[i].mEnqueued.reset();
+		mRequests[i].mDequeued.reset();
+		mRequests[i].mResponse.reset();
+	}
+}
+
+
 // ------------------------------------------------------
 // LLViewerAssetStats class definition
 // ------------------------------------------------------
@@ -81,20 +97,55 @@ LLViewerAssetStats::LLViewerAssetStats()
 void
 LLViewerAssetStats::reset()
 {
-	for (int i = 0; i < LL_ARRAY_SIZE(mRequests); ++i)
+	// Empty the map of all region stats
+	mRegionStats.clear();
+
+	// If we have a current stats, reset it, otherwise, as at construction,
+	// create a new one.
+	if (mCurRegionStats)
 	{
-		mRequests[i].mEnqueued.reset();
-		mRequests[i].mDequeued.reset();
-		mRequests[i].mResponse.reset();
+		mCurRegionStats->reset();
 	}
+	else
+	{
+		mCurRegionStats = new PerRegionStats(mRegionID);
+	}
+
+	// And add reference to map
+	mRegionStats[mRegionID] = mCurRegionStats;
 }
 
+
+void
+LLViewerAssetStats::setRegionID(const LLUUID & region_id)
+{
+	if (region_id == mRegionID)
+	{
+		// Already active, ignore.
+		return;
+	}
+	
+	PerRegionContainer::iterator new_stats = mRegionStats.find(region_id);
+	if (mRegionStats.end() == new_stats)
+	{
+		// Haven't seen this region_id before, create a new block make it current.
+		mCurRegionStats = new PerRegionStats(region_id);
+		mRegionStats[region_id] = mCurRegionStats;
+	}
+	else
+	{
+		mCurRegionStats = new_stats->second;
+	}
+	mRegionID = region_id;
+}
+
+
 void
 LLViewerAssetStats::recordGetEnqueued(LLViewerAssetType::EType at, bool with_http, bool is_temp)
 {
 	const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp));
 	
-	++mRequests[int(eac)].mEnqueued;
+	++(mCurRegionStats->mRequests[int(eac)].mEnqueued);
 }
 	
 void
@@ -102,7 +153,7 @@ LLViewerAssetStats::recordGetDequeued(LLViewerAssetType::EType at, bool with_htt
 {
 	const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp));
 
-	++mRequests[int(eac)].mDequeued;
+	++(mCurRegionStats->mRequests[int(eac)].mDequeued);
 }
 
 void
@@ -110,7 +161,7 @@ LLViewerAssetStats::recordGetServiced(LLViewerAssetType::EType at, bool with_htt
 {
 	const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp));
 
-	mRequests[int(eac)].mResponse.record(duration);
+	mCurRegionStats->mRequests[int(eac)].mResponse.record(duration);
 }
 
 const LLSD
@@ -139,16 +190,33 @@ LLViewerAssetStats::asLLSD() const
 	
 	LLSD ret = LLSD::emptyMap();
 
-	for (int i = 0; i < EVACCount; ++i)
+	for (PerRegionContainer::const_iterator it = mRegionStats.begin();
+		 mRegionStats.end() != it;
+		 ++it)
 	{
-		LLSD & slot = ret[tags[i]];
-		slot = LLSD::emptyMap();
-		slot[enq_tag] = LLSD(S32(mRequests[i].mEnqueued.getCount()));
-		slot[deq_tag] = LLSD(S32(mRequests[i].mDequeued.getCount()));
-		slot[rcnt_tag] = LLSD(S32(mRequests[i].mResponse.getCount()));
-		slot[rmin_tag] = LLSD(mRequests[i].mResponse.getMin());
-		slot[rmax_tag] = LLSD(mRequests[i].mResponse.getMax());
-		slot[rmean_tag] = LLSD(mRequests[i].mResponse.getMean());
+		if (it->first.isNull())
+		{
+			// Never emit NULL UUID in results.
+			continue;
+		}
+
+		const PerRegionStats & stats = *it->second;
+		
+		LLSD reg_stat = LLSD::emptyMap();
+		
+		for (int i = 0; i < EVACCount; ++i)
+		{
+			LLSD & slot = reg_stat[tags[i]];
+			slot = LLSD::emptyMap();
+			slot[enq_tag] = LLSD(S32(stats.mRequests[i].mEnqueued.getCount()));
+			slot[deq_tag] = LLSD(S32(stats.mRequests[i].mDequeued.getCount()));
+			slot[rcnt_tag] = LLSD(S32(stats.mRequests[i].mResponse.getCount()));
+			slot[rmin_tag] = LLSD(stats.mRequests[i].mResponse.getMin());
+			slot[rmax_tag] = LLSD(stats.mRequests[i].mResponse.getMax());
+			slot[rmean_tag] = LLSD(stats.mRequests[i].mResponse.getMean());
+		}
+
+		ret[it->first.asString()] = reg_stat;
 	}
 
 	return ret;
@@ -161,31 +229,81 @@ LLViewerAssetStats::asLLSD() const
 namespace LLViewerAssetStatsFF
 {
 
+// Target thread is elaborated in the function name.  This could
+// have been something 'templatey' like specializations iterated
+// over a set of constants but with so few, this is clearer I think.
+
+void
+set_region_main(const LLUUID & region_id)
+{
+	if (! gViewerAssetStatsMain)
+		return;
+
+	gViewerAssetStatsMain->setRegionID(region_id);
+}
+
+void
+record_enqueue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp)
+{
+	if (! gViewerAssetStatsMain)
+		return;
+
+	gViewerAssetStatsMain->recordGetEnqueued(at, with_http, is_temp);
+}
+
+void
+record_dequeue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp)
+{
+	if (! gViewerAssetStatsMain)
+		return;
+
+	gViewerAssetStatsMain->recordGetDequeued(at, with_http, is_temp);
+}
+
+void
+record_response_main(LLViewerAssetType::EType at, bool with_http, bool is_temp, F64 duration)
+{
+	if (! gViewerAssetStatsMain)
+		return;
+
+	gViewerAssetStatsMain->recordGetServiced(at, with_http, is_temp, duration);
+}
+
+
+void
+set_region_thread1(const LLUUID & region_id)
+{
+	if (! gViewerAssetStatsThread1)
+		return;
+
+	gViewerAssetStatsThread1->setRegionID(region_id);
+}
+
 void
-record_enqueue(LLViewerAssetType::EType at, bool with_http, bool is_temp)
+record_enqueue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp)
 {
-	if (! gViewerAssetStats)
+	if (! gViewerAssetStatsThread1)
 		return;
 
-	gViewerAssetStats->recordGetEnqueued(at, with_http, is_temp);
+	gViewerAssetStatsThread1->recordGetEnqueued(at, with_http, is_temp);
 }
 
 void
-record_dequeue(LLViewerAssetType::EType at, bool with_http, bool is_temp)
+record_dequeue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp)
 {
-	if (! gViewerAssetStats)
+	if (! gViewerAssetStatsThread1)
 		return;
 
-	gViewerAssetStats->recordGetDequeued(at, with_http, is_temp);
+	gViewerAssetStatsThread1->recordGetDequeued(at, with_http, is_temp);
 }
 
 void
-record_response(LLViewerAssetType::EType at, bool with_http, bool is_temp, F64 duration)
+record_response_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp, F64 duration)
 {
-	if (! gViewerAssetStats)
+	if (! gViewerAssetStatsThread1)
 		return;
 
-	gViewerAssetStats->recordGetServiced(at, with_http, is_temp, duration);
+	gViewerAssetStatsThread1->recordGetServiced(at, with_http, is_temp, duration);
 }
 
 } // namespace LLViewerAssetStatsFF
diff --git a/indra/newview/llviewerassetstats.h b/indra/newview/llviewerassetstats.h
index 9d66a1e89b..b8356a5ff5 100644
--- a/indra/newview/llviewerassetstats.h
+++ b/indra/newview/llviewerassetstats.h
@@ -36,6 +36,8 @@
 
 #include "linden_common.h"
 
+#include "llpointer.h"
+#include "llrefcount.h"
 #include "llviewerassettype.h"
 #include "llviewerassetstorage.h"
 #include "llsimplestat.h"
@@ -43,50 +45,42 @@
 
 /**
  * @class LLViewerAssetStats
- * @brief Records events and performance of asset put/get operations.
+ * @brief Records performance aspects of asset access operations.
  *
- * The asset system is a combination of common code and server-
- * and viewer-overridden derivations.  The common code is presented
- * in here as the 'front-end' and deriviations (really the server)
- * are presented as 'back-end'.  The distinction isn't perfect as
- * there are legacy asset transfer systems which mostly appear
- * as front-end stats.
+ * This facility is derived from a very similar simulator-based
+ * one, LLSimAssetStats.  It's function is to count asset access
+ * operations and characterize response times.  Collected data
+ * are binned in several dimensions:
+ *
+ *  - Asset types collapsed into a few aggregated categories
+ *  - By simulator UUID
+ *  - By transport mechanism (HTTP vs MessageSystem)
+ *  - By persistence (temp vs non-temp)
+ *
+ * Statistics collected are fairly basic at this point:
  *
- * Statistics collected are fairly basic:
  *  - Counts of enqueue and dequeue operations
- *  - Counts of duplicated request fetches
  *  - Min/Max/Mean of asset transfer operations
  *
- * While the stats collection interfaces appear to be fairly
- * orthogonal across methods (GET, PUT) and asset types (texture,
- * bodypart, etc.), the actual internal collection granularity
- * varies greatly.  GET's operations found in the cache are
- * treated as a single group as are duplicate requests.  Non-
- * cached items are broken down into three groups:  textures,
- * wearables (bodyparts, clothing) and the rest.  PUT operations
- * are broken down into two categories:  temporary assets and
- * non-temp.  Back-end operations do not distinguish asset types,
- * only GET, PUT (temp) and PUT (non-temp).
- * 
- * No coverage for Estate Assets or Inventory Item Assets which use
- * some different interface conventions.  It could be expanded to cover
- * them.
+ * This collector differs from the simulator-based on in a
+ * number of ways:
+ *
+ *  - The front-end/back-end distinction doesn't exist in viewer
+ *    code
+ *  - Multiple threads must be safely accomodated in the viewer
  *
  * Access to results is by conversion to an LLSD with some standardized
- * key names.  The intent of this structure is to be emitted as
+ * key names.  The intent of this structure is that it be emitted as
  * standard syslog-based metrics formatting where it can be picked
  * up by interested parties.
  *
- * For convenience, a set of free functions in namespace LLAssetStatsFF
- * are provided which operate on various counters in a way that
- * is highly-compatible with the simulator code.
+ * For convenience, a set of free functions in namespace
+ * LLViewerAssetStatsFF is provided for conditional test-and-call
+ * operations.
  */
 class LLViewerAssetStats
 {
 public:
-	LLViewerAssetStats();
-	// Default destructor and assignment operator are correct.
-	
 	enum EViewerAssetCategories
 	{
 		EVACTextureTempHTTPGet,			//< Texture GETs
@@ -100,45 +94,109 @@ public:
 		
 		EVACCount						// Must be last
 	};
-	
+
+	/**
+	 * Collected data for a single region visited by the avatar.
+	 */
+	class PerRegionStats : public LLRefCount
+	{
+	public:
+		PerRegionStats(const LLUUID & region_id)
+			: LLRefCount(),
+			  mRegionID(region_id)
+			{
+				reset();
+			}
+		
+		void reset();
+
+	public:
+		LLUUID mRegionID;
+		struct
+		{
+			LLSimpleStatCounter		mEnqueued;
+			LLSimpleStatCounter		mDequeued;
+			LLSimpleStatMMM<>		mResponse;
+		} mRequests [EVACCount];
+	};
+
+public:
+	LLViewerAssetStats();
+	// Default destructor is correct.
+	LLViewerAssetStats & operator=(const LLViewerAssetStats &);			// Not defined
+
+	// Clear all metrics data.  This leaves the currently-active region
+	// in place but with zero'd data for all metrics.  All other regions
+	// are removed from the collection map.
 	void reset();
 
+	// Set hidden region argument and establish context for subsequent
+	// collection calls.
+	void setRegionID(const LLUUID & region_id);
+
 	// Non-Cached GET Requests
 	void recordGetEnqueued(LLViewerAssetType::EType at, bool with_http, bool is_temp);
 	void recordGetDequeued(LLViewerAssetType::EType at, bool with_http, bool is_temp);
 	void recordGetServiced(LLViewerAssetType::EType at, bool with_http, bool is_temp, F64 duration);
 
-	// Report Generation
+	// Retrieve current metrics for all visited regions.
 	const LLSD asLLSD() const;
 	
 protected:
+	typedef std::map<LLUUID, LLPointer<PerRegionStats> > PerRegionContainer;
 
-	struct 
-	{
-		LLSimpleStatCounter		mEnqueued;
-		LLSimpleStatCounter		mDequeued;
-		LLSimpleStatMMM<>		mResponse;
-	} mRequests [EVACCount];
+	// Region of the currently-active region.  Always valid but may
+	// be a NULL UUID after construction or when explicitly set.  Unchanged
+	// by a reset() call.
+	LLUUID mRegionID;
+
+	// Pointer to metrics collection for currently-active region.  Always
+	// valid and unchanged after reset() though contents will be changed.
+	// Always points to a collection contained in mRegionStats.
+	LLPointer<PerRegionStats> mCurRegionStats;
+
+	// Metrics data for all regions during one collection cycle
+	PerRegionContainer mRegionStats;
 };
 
 
 /**
- * Expectation is that the simulator and other asset-handling
- * code will create a single instance of the stats class and
- * make it available here.  The free functions examine this
- * for non-zero and perform their functions conditionally.  The
- * instance methods themselves make no assumption about this.
+ * Global stats collectors one for each independent thread where
+ * assets and other statistics are gathered.  The globals are
+ * expected to be created at startup time and then picked up by
+ * their respective threads afterwards.  A set of free functions
+ * are provided to access methods behind the globals while both
+ * minimally disrupting visual flow and supplying a description
+ * of intent.
+ *
+ * Expected thread assignments:
+ *
+ *  - Main:  main() program execution thread
+ *  - Thread1:  TextureFetch worker thread
  */
-extern LLViewerAssetStats * gViewerAssetStats;
+extern LLViewerAssetStats * gViewerAssetStatsMain;
+
+extern LLViewerAssetStats * gViewerAssetStatsThread1;
 
 namespace LLViewerAssetStatsFF
 {
 
-void record_enqueue(LLViewerAssetType::EType at, bool with_http, bool is_temp);
+void set_region_main(const LLUUID & region_id);
+
+void record_enqueue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp);
+
+void record_dequeue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp);
+
+void record_response_main(LLViewerAssetType::EType at, bool with_http, bool is_temp, F64 duration);
+
+
+void set_region_thread1(const LLUUID & region_id);
+
+void record_enqueue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp);
 
-void record_dequeue(LLViewerAssetType::EType at, bool with_http, bool is_temp);
+void record_dequeue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp);
 
-void record_response(LLViewerAssetType::EType at, bool with_http, bool is_temp, F64 duration);
+void record_response_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp, F64 duration);
 
 } // namespace LLViewerAssetStatsFF
 
diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp
index 50d348c7e3..affe16c177 100644
--- a/indra/newview/tests/llviewerassetstats_test.cpp
+++ b/indra/newview/tests/llviewerassetstats_test.cpp
@@ -38,6 +38,7 @@
 
 #include "lltut.h"
 #include "../llviewerassetstats.h"
+#include "lluuid.h"
 
 static const char * all_keys[] = 
 {
@@ -73,6 +74,27 @@ static const char * sub_keys[] =
 	"resp_mean"
 };
 
+static const LLUUID region1("4e2d81a3-6263-6ffe-ad5c-8ce04bee07e8");
+static const LLUUID region2("68762cc8-b68b-4e45-854b-e830734f2d4a");
+
+static bool
+is_empty_map(const LLSD & sd)
+{
+	return sd.isMap() && 0 == sd.size();
+}
+
+static bool
+is_single_key_map(const LLSD & sd, const std::string & key)
+{
+	return sd.isMap() && 1 == sd.size() && sd.has(key);
+}
+
+static bool
+is_double_key_map(const LLSD & sd, const std::string & key1, const std::string & key2)
+{
+	return sd.isMap() && 2 == sd.size() && sd.has(key1) && sd.has(key2);
+}
+
 namespace tut
 {
 	struct tst_viewerassetstats_index
@@ -86,29 +108,40 @@ namespace tut
 	void tst_viewerassetstats_index_object_t::test<1>()
 	{
 		// Check that helpers aren't bothered by missing global stats
-		ensure("Global gViewerAssetStats should be NULL", (NULL == gViewerAssetStats));
+		ensure("Global gViewerAssetStatsMain should be NULL", (NULL == gViewerAssetStatsMain));
 
-		LLViewerAssetStatsFF::record_enqueue(LLViewerAssetType::AT_TEXTURE, false, false);
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false);
 
-		LLViewerAssetStatsFF::record_dequeue(LLViewerAssetType::AT_TEXTURE, false, false);
+		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false);
 
-		LLViewerAssetStatsFF::record_response(LLViewerAssetType::AT_GESTURE, false, false, 12.3);
+		LLViewerAssetStatsFF::record_response_main(LLViewerAssetType::AT_GESTURE, false, false, 12.3);
 	}
 
 	// Create a non-global instance and check the structure
 	template<> template<>
 	void tst_viewerassetstats_index_object_t::test<2>()
 	{
-		ensure("Global gViewerAssetStats should be NULL", (NULL == gViewerAssetStats));
+		ensure("Global gViewerAssetStatsMain should be NULL", (NULL == gViewerAssetStatsMain));
 
 		LLViewerAssetStats * it = new LLViewerAssetStats();
 
-		ensure("Global gViewerAssetStats should still be NULL", (NULL == gViewerAssetStats));
-		
-		LLSD sd = it->asLLSD();
-		
-		delete it;
+		ensure("Global gViewerAssetStatsMain should still be NULL", (NULL == gViewerAssetStatsMain));
 
+		LLSD sd_full = it->asLLSD();
+
+		// Default (NULL) region ID doesn't produce LLSD results so should
+		// get an empty map back from output
+		ensure("Null LLSD initially", is_empty_map(sd_full));
+
+		// Once the region is set, we will get a response even with no data collection
+		it->setRegionID(region1);
+		sd_full = it->asLLSD();
+		ensure("Correct single-key LLSD map", is_single_key_map(sd_full, region1.asString()));
+
+		LLSD sd = sd_full[region1.asString()];
+
+		delete it;
+			
 		// Check the structure of the LLSD
 		for (int i = 0; i < LL_ARRAY_SIZE(all_keys); ++i)
 		{
@@ -131,8 +164,11 @@ namespace tut
 	void tst_viewerassetstats_index_object_t::test<3>()
 	{
 		LLViewerAssetStats * it = new LLViewerAssetStats();
+		it->setRegionID(region1);
 		
 		LLSD sd = it->asLLSD();
+		ensure("Correct single-key LLSD map", is_single_key_map(sd, region1.asString()));
+		sd = sd[region1.asString()];
 		
 		delete it;
 
@@ -145,15 +181,57 @@ namespace tut
 	template<> template<>
 	void tst_viewerassetstats_index_object_t::test<4>()
 	{
-		gViewerAssetStats = new LLViewerAssetStats();
+		gViewerAssetStatsMain = new LLViewerAssetStats();
+		LLViewerAssetStatsFF::set_region_main(region1);
+
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false);
+		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false);
+
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false);
+		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false);
+
+		LLSD sd = gViewerAssetStatsMain->asLLSD();
+		ensure("Correct single-key LLSD map", is_single_key_map(sd, region1.asString()));
+		sd = sd[region1.asString()];
+		
+		// Check a few points on the tree for content
+		ensure("sd[get_texture_non_temp_udp][enqueued] is 1", (1 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger()));
+		ensure("sd[get_texture_temp_udp][enqueued] is 0", (0 == sd["get_texture_temp_udp"]["enqueued"].asInteger()));
+		ensure("sd[get_texture_non_temp_http][enqueued] is 0", (0 == sd["get_texture_non_temp_http"]["enqueued"].asInteger()));
+		ensure("sd[get_texture_temp_http][enqueued] is 0", (0 == sd["get_texture_temp_http"]["enqueued"].asInteger()));
+		ensure("sd[get_gesture_udp][dequeued] is 0", (0 == sd["get_gesture_udp"]["dequeued"].asInteger()));
+
+		// Reset and check zeros...
+		// Reset leaves current region in place
+		gViewerAssetStatsMain->reset();
+		sd = gViewerAssetStatsMain->asLLSD()[region1.asString()];
+		
+		delete gViewerAssetStatsMain;
+		gViewerAssetStatsMain = NULL;
+
+		ensure("sd[get_texture_non_temp_udp][enqueued] is reset", (0 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger()));
+		ensure("sd[get_gesture_udp][dequeued] is reset", (0 == sd["get_gesture_udp"]["dequeued"].asInteger()));
+	}
+
+	// Create two global instances and verify no interactions
+	template<> template<>
+	void tst_viewerassetstats_index_object_t::test<5>()
+	{
+		gViewerAssetStatsThread1 = new LLViewerAssetStats();
+		gViewerAssetStatsMain = new LLViewerAssetStats();
+		LLViewerAssetStatsFF::set_region_main(region1);
 
-		LLViewerAssetStatsFF::record_enqueue(LLViewerAssetType::AT_TEXTURE, false, false);
-		LLViewerAssetStatsFF::record_dequeue(LLViewerAssetType::AT_TEXTURE, false, false);
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false);
+		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false);
 
-		LLViewerAssetStatsFF::record_enqueue(LLViewerAssetType::AT_BODYPART, false, false);
-		LLViewerAssetStatsFF::record_dequeue(LLViewerAssetType::AT_BODYPART, false, false);
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false);
+		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false);
 
-		LLSD sd = gViewerAssetStats->asLLSD();
+		LLSD sd = gViewerAssetStatsThread1->asLLSD();
+		ensure("Other collector is empty", is_empty_map(sd));
+		sd = gViewerAssetStatsMain->asLLSD();
+		ensure("Correct single-key LLSD map", is_single_key_map(sd, region1.asString()));
+		sd = sd[region1.asString()];
 		
 		// Check a few points on the tree for content
 		ensure("sd[get_texture_non_temp_udp][enqueued] is 1", (1 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger()));
@@ -163,11 +241,196 @@ namespace tut
 		ensure("sd[get_gesture_udp][dequeued] is 0", (0 == sd["get_gesture_udp"]["dequeued"].asInteger()));
 
 		// Reset and check zeros...
-		gViewerAssetStats->reset();
-		sd = gViewerAssetStats->asLLSD();
+		// Reset leaves current region in place
+		gViewerAssetStatsMain->reset();
+		sd = gViewerAssetStatsMain->asLLSD()[region1.asString()];
+		
+		delete gViewerAssetStatsMain;
+		gViewerAssetStatsMain = NULL;
+		delete gViewerAssetStatsThread1;
+		gViewerAssetStatsThread1 = NULL;
+
+		ensure("sd[get_texture_non_temp_udp][enqueued] is reset", (0 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger()));
+		ensure("sd[get_gesture_udp][dequeued] is reset", (0 == sd["get_gesture_udp"]["dequeued"].asInteger()));
+	}
+
+    // Check multiple region collection
+	template<> template<>
+	void tst_viewerassetstats_index_object_t::test<6>()
+	{
+		gViewerAssetStatsMain = new LLViewerAssetStats();
+
+		LLViewerAssetStatsFF::set_region_main(region1);
+
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false);
+		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false);
+
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false);
+		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false);
+
+		LLViewerAssetStatsFF::set_region_main(region2);
+
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
+
+		LLSD sd = gViewerAssetStatsMain->asLLSD();
+
+		ensure("Correct double-key LLSD map", is_double_key_map(sd, region1.asString(), region2.asString()));
+		LLSD sd1 = sd[region1.asString()];
+		LLSD sd2 = sd[region2.asString()];
+		
+		// Check a few points on the tree for content
+		ensure("sd1[get_texture_non_temp_udp][enqueued] is 1", (1 == sd1["get_texture_non_temp_udp"]["enqueued"].asInteger()));
+		ensure("sd1[get_texture_temp_udp][enqueued] is 0", (0 == sd1["get_texture_temp_udp"]["enqueued"].asInteger()));
+		ensure("sd1[get_texture_non_temp_http][enqueued] is 0", (0 == sd1["get_texture_non_temp_http"]["enqueued"].asInteger()));
+		ensure("sd1[get_texture_temp_http][enqueued] is 0", (0 == sd1["get_texture_temp_http"]["enqueued"].asInteger()));
+		ensure("sd1[get_gesture_udp][dequeued] is 0", (0 == sd1["get_gesture_udp"]["dequeued"].asInteger()));
+
+		// Check a few points on the tree for content
+		ensure("sd2[get_gesture_udp][enqueued] is 4", (4 == sd2["get_gesture_udp"]["enqueued"].asInteger()));
+		ensure("sd2[get_gesture_udp][dequeued] is 0", (0 == sd2["get_gesture_udp"]["dequeued"].asInteger()));
+		ensure("sd2[get_texture_non_temp_udp][enqueued] is 0", (0 == sd2["get_texture_non_temp_udp"]["enqueued"].asInteger()));
+
+		// Reset and check zeros...
+		// Reset leaves current region in place
+		gViewerAssetStatsMain->reset();
+		sd = gViewerAssetStatsMain->asLLSD();
+		ensure("Correct single-key LLSD map", is_single_key_map(sd, region2.asString()));
+		sd2 = sd[region2.asString()];
+		
+		delete gViewerAssetStatsMain;
+		gViewerAssetStatsMain = NULL;
+
+		ensure("sd2[get_texture_non_temp_udp][enqueued] is reset", (0 == sd2["get_texture_non_temp_udp"]["enqueued"].asInteger()));
+		ensure("sd2[get_gesture_udp][enqueued] is reset", (0 == sd2["get_gesture_udp"]["enqueued"].asInteger()));
+	}
+
+    // Check multiple region collection jumping back-and-forth between regions
+	template<> template<>
+	void tst_viewerassetstats_index_object_t::test<7>()
+	{
+		gViewerAssetStatsMain = new LLViewerAssetStats();
+
+		LLViewerAssetStatsFF::set_region_main(region1);
+
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false);
+		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false);
+
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false);
+		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false);
+
+		LLViewerAssetStatsFF::set_region_main(region2);
+
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
+
+		LLViewerAssetStatsFF::set_region_main(region1);
+
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, true, true);
+		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, true, true);
+
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false);
+		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false);
+
+		LLViewerAssetStatsFF::set_region_main(region2);
+
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
+
+		LLSD sd = gViewerAssetStatsMain->asLLSD();
+
+		ensure("Correct double-key LLSD map", is_double_key_map(sd, region1.asString(), region2.asString()));
+		LLSD sd1 = sd[region1.asString()];
+		LLSD sd2 = sd[region2.asString()];
+		
+		// Check a few points on the tree for content
+		ensure("sd1[get_texture_non_temp_udp][enqueued] is 1", (1 == sd1["get_texture_non_temp_udp"]["enqueued"].asInteger()));
+		ensure("sd1[get_texture_temp_udp][enqueued] is 0", (0 == sd1["get_texture_temp_udp"]["enqueued"].asInteger()));
+		ensure("sd1[get_texture_non_temp_http][enqueued] is 0", (0 == sd1["get_texture_non_temp_http"]["enqueued"].asInteger()));
+		ensure("sd1[get_texture_temp_http][enqueued] is 1", (1 == sd1["get_texture_temp_http"]["enqueued"].asInteger()));
+		ensure("sd1[get_gesture_udp][dequeued] is 0", (0 == sd1["get_gesture_udp"]["dequeued"].asInteger()));
+
+		// Check a few points on the tree for content
+		ensure("sd2[get_gesture_udp][enqueued] is 8", (8 == sd2["get_gesture_udp"]["enqueued"].asInteger()));
+		ensure("sd2[get_gesture_udp][dequeued] is 0", (0 == sd2["get_gesture_udp"]["dequeued"].asInteger()));
+		ensure("sd2[get_texture_non_temp_udp][enqueued] is 0", (0 == sd2["get_texture_non_temp_udp"]["enqueued"].asInteger()));
+
+		// Reset and check zeros...
+		// Reset leaves current region in place
+		gViewerAssetStatsMain->reset();
+		sd = gViewerAssetStatsMain->asLLSD();
+		ensure("Correct single-key LLSD map", is_single_key_map(sd, region2.asString()));
+		sd2 = sd[region2.asString()];
+		
+		delete gViewerAssetStatsMain;
+		gViewerAssetStatsMain = NULL;
+
+		ensure("sd2[get_texture_non_temp_udp][enqueued] is reset", (0 == sd2["get_texture_non_temp_udp"]["enqueued"].asInteger()));
+		ensure("sd2[get_gesture_udp][enqueued] is reset", (0 == sd2["get_gesture_udp"]["enqueued"].asInteger()));
+	}
+
+	// Non-texture assets ignore transport and persistence flags
+	template<> template<>
+	void tst_viewerassetstats_index_object_t::test<8>()
+	{
+		gViewerAssetStatsThread1 = new LLViewerAssetStats();
+		gViewerAssetStatsMain = new LLViewerAssetStats();
+		LLViewerAssetStatsFF::set_region_main(region1);
+
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false);
+		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false);
+
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false);
+		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false);
+
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, true);
+		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, true);
+
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, true, false);
+		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, true, false);
+
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, true, true);
+		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, true, true);
+
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_LSL_BYTECODE, false, false);
+
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_LSL_BYTECODE, false, true);
+
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_LSL_BYTECODE, true, false);
+
+		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+		LLSD sd = gViewerAssetStatsThread1->asLLSD();
+		ensure("Other collector is empty", is_empty_map(sd));
+		sd = gViewerAssetStatsMain->asLLSD();
+		ensure("Correct single-key LLSD map", is_single_key_map(sd, region1.asString()));
+		sd = sd[region1.asString()];
+		
+		// Check a few points on the tree for content
+		ensure("sd[get_gesture_udp][enqueued] is 0", (0 == sd["get_gesture_udp"]["enqueued"].asInteger()));
+		ensure("sd[get_gesture_udp][dequeued] is 0", (0 == sd["get_gesture_udp"]["dequeued"].asInteger()));
+
+		ensure("sd[get_wearable_udp][enqueued] is 4", (4 == sd["get_wearable_udp"]["enqueued"].asInteger()));
+		ensure("sd[get_wearable_udp][dequeued] is 4", (4 == sd["get_wearable_udp"]["dequeued"].asInteger()));
+
+		ensure("sd[get_other][enqueued] is 4", (4 == sd["get_other"]["enqueued"].asInteger()));
+		ensure("sd[get_other][dequeued] is 0", (0 == sd["get_other"]["dequeued"].asInteger()));
+
+		// Reset and check zeros...
+		// Reset leaves current region in place
+		gViewerAssetStatsMain->reset();
+		sd = gViewerAssetStatsMain->asLLSD()[region1.asString()];
 		
-		delete gViewerAssetStats;
-		gViewerAssetStats = NULL;
+		delete gViewerAssetStatsMain;
+		gViewerAssetStatsMain = NULL;
+		delete gViewerAssetStatsThread1;
+		gViewerAssetStatsThread1 = NULL;
 
 		ensure("sd[get_texture_non_temp_udp][enqueued] is reset", (0 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger()));
 		ensure("sd[get_gesture_udp][dequeued] is reset", (0 == sd["get_gesture_udp"]["dequeued"].asInteger()));
-- 
cgit v1.2.3


From deeef0c73ead965f7202bb5ac4c8481354f3b08e Mon Sep 17 00:00:00 2001
From: Monty Brandenberg <monty@lindenlab.com>
Date: Wed, 10 Nov 2010 10:13:31 -0800
Subject: Need precompiled header include for windows.

---
 indra/newview/llviewerassetstats.cpp | 2 ++
 1 file changed, 2 insertions(+)

(limited to 'indra/newview')

diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp
index a6c4685bf1..37e7c43f36 100644
--- a/indra/newview/llviewerassetstats.cpp
+++ b/indra/newview/llviewerassetstats.cpp
@@ -30,6 +30,8 @@
  * $/LicenseInfo$
  */
 
+#include "llviewerprecompiledheaders.h"
+
 #include "llviewerassetstats.h"
 
 #include "stdtypes.h"
-- 
cgit v1.2.3


From d276950c8d4d53f9d5d6497d5a4a4582c499938a Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Mon, 15 Nov 2010 17:03:52 -0800
Subject: build fixes

---
 indra/newview/llpaneloutfitedit.cpp | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp
index ce9b1c66d7..c10c21683b 100644
--- a/indra/newview/llpaneloutfitedit.cpp
+++ b/indra/newview/llpaneloutfitedit.cpp
@@ -186,14 +186,8 @@ private:
 	// Populate the menu with items like "New Skin", "New Pants", etc.
 	static void populateCreateWearableSubmenus(LLMenuGL* menu)
 	{
-		LLView* menu_clothes	= gMenuHolder->findChildView("COF.Gear.New_Clothes", FALSE);
-		LLView* menu_bp			= gMenuHolder->findChildView("COF.Geear.New_Body_Parts", FALSE);
-
-		if (!menu_clothes || !menu_bp)
-		{
-			llassert(menu_clothes && menu_bp);
-			return;
-		}
+		LLView* menu_clothes	= gMenuHolder->getChildView("COF.Gear.New_Clothes", FALSE);
+		LLView* menu_bp			= gMenuHolder->getChildView("COF.Geear.New_Body_Parts", FALSE);
 
 		for (U8 i = LLWearableType::WT_SHAPE; i != (U8) LLWearableType::WT_COUNT; ++i)
 		{
-- 
cgit v1.2.3


From d666a3d92cb5dd9844c29e5472db542de7b5ac9e Mon Sep 17 00:00:00 2001
From: Monty Brandenberg <monty@lindenlab.com>
Date: Thu, 18 Nov 2010 08:43:09 -0800
Subject: ESC-154 ESC-155 ESC-156 Asset fetch requests wrapped to allow for
 measurements. Asset fetch enqueues, dequeues and completion times recorded to
 asset stats collector.  Texture fetch operations (http and udp) recorded to
 asset stats collector.  Stats collector time vallue switched from F32 to U64
 which is the more common type in the viewer.  Cross-thread mechanism
 introduced to communicate region changes and generate global statistics
 messages.  Facility to deliver metrics via Capabilities sketched in but needs
 additional work.  Documentation and diagrams added.

---
 indra/newview/llagent.cpp                       |   3 +
 indra/newview/llappviewer.cpp                   | 114 ++++++
 indra/newview/llappviewer.h                     |   4 +
 indra/newview/lltexturefetch.cpp                | 488 +++++++++++++++++++++++-
 indra/newview/lltexturefetch.h                  |  33 +-
 indra/newview/llviewerassetstats.cpp            |  87 ++++-
 indra/newview/llviewerassetstats.h              |  48 ++-
 indra/newview/llviewerassetstorage.cpp          | 124 ++++++
 indra/newview/llviewerassetstorage.h            |  11 +
 indra/newview/llviewerregion.cpp                |   1 +
 indra/newview/tests/llviewerassetstats_test.cpp |   2 +-
 11 files changed, 893 insertions(+), 22 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index c9bd7851ed..e2b1c89402 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -637,6 +637,9 @@ void LLAgent::setRegion(LLViewerRegion *regionp)
 			// Update all of the regions.
 			LLWorld::getInstance()->updateAgentOffset(mAgentOriginGlobal);
 		}
+
+		// Pass new region along to metrics components that care about this level of detail.
+		LLAppViewer::metricsUpdateRegion(regionp->getRegionID());
 	}
 	mRegionp = regionp;
 
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 333c92e50d..2e056238e4 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -190,6 +190,7 @@
 #include "llparcel.h"
 #include "llavatariconctrl.h"
 #include "llgroupiconctrl.h"
+#include "llviewerassetstats.h"
 
 // Include for security api initialization
 #include "llsecapi.h"
@@ -332,6 +333,14 @@ static std::string gWindowTitle;
 
 LLAppViewer::LLUpdaterInfo *LLAppViewer::sUpdaterInfo = NULL ;
 
+//----------------------------------------------------------------------------
+// Metrics logging control constants
+//----------------------------------------------------------------------------
+static const F32 METRICS_INTERVAL_MIN = 300.0;
+static const F32 METRICS_INTERVAL_MAX = 3600.0;
+static const F32 METRICS_INTERVAL_DEFAULT = 600.0;
+
+
 void idle_afk_check()
 {
 	// check idle timers
@@ -656,6 +665,8 @@ bool LLAppViewer::init()
     LLCurl::initClass();
     LLMachineID::init();
 
+	LLViewerAssetStatsFF::init();
+
     initThreads();
     writeSystemInfo();
 
@@ -1670,6 +1681,8 @@ bool LLAppViewer::cleanup()
 
 	LLWatchdog::getInstance()->cleanup();
 
+	LLViewerAssetStatsFF::cleanup();
+	
 	llinfos << "Shutting down message system" << llendflush;
 	end_messaging_system();
 
@@ -3683,6 +3696,18 @@ void LLAppViewer::idle()
 		gInventory.idleNotifyObservers();
 	}
 	
+	// Metrics logging (LLViewerAssetStats, etc.)
+	{
+		static LLTimer report_interval;
+
+		// *TODO:  Add configuration controls for this
+		if (report_interval.getElapsedTimeF32() >= METRICS_INTERVAL_DEFAULT)
+		{
+			metricsIdle(! gDisconnected);
+			report_interval.reset();
+		}
+	}
+
 	if (gDisconnected)
     {
 		return;
@@ -4525,3 +4550,92 @@ bool LLAppViewer::getMasterSystemAudioMute()
 {
 	return gSavedSettings.getBOOL("MuteAudio");
 }
+
+//----------------------------------------------------------------------------
+// Metrics-related methods (static and otherwise)
+//----------------------------------------------------------------------------
+
+/**
+ * LLViewerAssetStats collects data on a per-region (as defined by the agent's
+ * location) so we need to tell it about region changes which become a kind of
+ * hidden variable/global state in the collectors.  For collectors not running
+ * on the main thread, we need to send a message to move the data over safely
+ * and cheaply (amortized over a run).
+ */
+void LLAppViewer::metricsUpdateRegion(const LLUUID & region_id)
+{
+	if (! region_id.isNull())
+	{
+		LLViewerAssetStatsFF::set_region_main(region_id);
+		if (LLAppViewer::sTextureFetch)
+		{
+			// Send a region update message into 'thread1' to get the new region.
+			LLAppViewer::sTextureFetch->commandSetRegion(region_id);
+		}
+		else
+		{
+			// No 'thread1', a.k.a. TextureFetch, so update directly
+			LLViewerAssetStatsFF::set_region_thread1(region_id);
+		}
+	}
+}
+
+
+/**
+ * Attempts to start a multi-threaded metrics report to be sent back to
+ * the grid for consumption.
+ */
+void LLAppViewer::metricsIdle(bool enable_reporting)
+{
+	if (! gViewerAssetStatsMain)
+		return;
+
+	std::string caps_url;
+	LLViewerRegion * regionp = gAgent.getRegion();
+	if (regionp)
+	{
+		caps_url = regionp->getCapability("ViewerMetrics");
+		caps_url = "http://localhost:80/putz/";
+	}
+	
+	if (enable_reporting && regionp && ! caps_url.empty())
+	{
+		// *NOTE:  Pay attention here.  LLSD's are not safe for thread sharing
+		// and their ownership is difficult to transfer across threads.  We do
+		// it here by having only one reference (the new'd pointer) to the LLSD
+		// or any subtree of it.  This pointer is then transfered to the other
+		// thread using correct thread logic.
+		
+		LLSD * envelope = new LLSD(LLSD::emptyMap());
+		{
+			(*envelope)["session_id"] = gAgentSessionID;
+			(*envelope)["agent_id"] = gAgentID;
+			(*envelope)["regions"] = gViewerAssetStatsMain->asLLSD();
+		}
+		
+		if (LLAppViewer::sTextureFetch)
+		{
+			// Send a report request into 'thread1' to get the rest of the data
+			// and have it sent to the stats collector.  LLSD ownership transfers
+			// with this call.
+			LLAppViewer::sTextureFetch->commandSendMetrics(caps_url, envelope);
+			envelope = 0;			// transfer noted
+		}
+		else
+		{
+			// No 'thread1' so transfer doesn't happen and we need to clean up
+			delete envelope;
+			envelope = 0;
+		}
+	}
+	else
+	{
+		LLAppViewer::sTextureFetch->commandDataBreak();
+	}
+
+	// Reset even if we can't report.  Rather than gather up a huge chunk of
+	// data, we'll keep to our sampling interval and retain the data
+	// resolution in time.
+	gViewerAssetStatsMain->reset();
+}
+
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 56d88f07c8..909f191ab1 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -167,6 +167,10 @@ public:
 	// mute/unmute the system's master audio
 	virtual void setMasterSystemAudioMute(bool mute);
 	virtual bool getMasterSystemAudioMute();
+
+	// Metrics policy helper statics.
+	static void metricsUpdateRegion(const LLUUID & region_id);
+	static void metricsIdle(bool enable_reporting);
 	
 protected:
 	virtual bool initWindow(); // Initialize the viewer's window.
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index fafef84aa2..df99818ee9 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -49,6 +49,7 @@
 #include "llviewertexture.h"
 #include "llviewerregion.h"
 #include "llviewerstats.h"
+#include "llviewerassetstats.h"
 #include "llworld.h"
 
 //////////////////////////////////////////////////////////////////////////////
@@ -143,7 +144,7 @@ public:
 	/*virtual*/ bool deleteOK(); // called from update() (WORK THREAD)
 
 	~LLTextureFetchWorker();
-	void relese() { --mActiveCount; }
+	// void relese() { --mActiveCount; }
 
 	S32 callbackHttpGet(const LLChannelDescriptors& channels,
 						 const LLIOPipe::buffer_ptr_t& buffer,
@@ -161,9 +162,11 @@ public:
 		mGetReason = reason;
 	}
 
-	void setCanUseHTTP(bool can_use_http) {mCanUseHTTP = can_use_http;}
-	bool getCanUseHTTP()const {return mCanUseHTTP ;}
+	void setCanUseHTTP(bool can_use_http) { mCanUseHTTP = can_use_http; }
+	bool getCanUseHTTP() const { return mCanUseHTTP; }
 
+	LLTextureFetch & getFetcher() { return *mFetcher; }
+	
 protected:
 	LLTextureFetchWorker(LLTextureFetch* fetcher, const std::string& url, const LLUUID& id, const LLHost& host,
 						 F32 priority, S32 discard, S32 size);
@@ -277,6 +280,8 @@ private:
 	S32 mLastPacket;
 	U16 mTotalPackets;
 	U8 mImageCodec;
+
+	LLViewerAssetStats::duration_t mMetricsStartTime;
 };
 
 //////////////////////////////////////////////////////////////////////////////
@@ -333,6 +338,18 @@ public:
 			
 			S32 data_size = worker->callbackHttpGet(channels, buffer, partial, success);
 			mFetcher->removeFromHTTPQueue(mID, data_size);
+
+			if (worker->mMetricsStartTime)
+			{
+				LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE,
+															  true,
+															  LLImageBase::TYPE_AVATAR_BAKE == worker->mType,
+															  LLViewerAssetStatsFF::get_timestamp() - worker->mMetricsStartTime);
+				worker->mMetricsStartTime = 0;
+			}
+			LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE,
+														 true,
+														 LLImageBase::TYPE_AVATAR_BAKE == worker->mType);
 		}
 		else
 		{
@@ -355,6 +372,201 @@ private:
 	bool mFollowRedir;
 };
 
+//////////////////////////////////////////////////////////////////////////////
+
+// Cross-thread messaging for asset metrics.
+
+namespace
+{
+
+/**
+ * @brief Base class for cross-thread requests made of the fetcher
+ *
+ * I believe the intent of the LLQueuedThread class was to
+ * have these operations derived from LLQueuedThread::QueuedRequest
+ * but the texture fetcher has elected to manage the queue
+ * in its own manner.  So these are free-standing objects which are
+ * managed in simple FIFO order on the mCommands queue of the
+ * LLTextureFetch object.
+ *
+ * What each represents is a simple command sent from an
+ * outside thread into the TextureFetch thread to be processed
+ * in order and in a timely fashion (though not an absolute
+ * higher priority than other operations of the thread).
+ * Each operation derives a new class from the base customizing
+ * members, constructors and the doWork() method to effect
+ * the command.
+ *
+ * The flow is one-directional.  There are two global instances
+ * of the LLViewerAssetStats collector, one for the main program's
+ * thread pointed to by gViewerAssetStatsMain and one for the
+ * TextureFetch thread pointed to by gViewerAssetStatsThread1.
+ * Common operations has each thread recording metrics events
+ * into the respective collector unconcerned with locking and
+ * the state of any other thread.  But when the agent moves into
+ * a different region or the metrics timer expires and a report
+ * needs to be sent back to the grid, messaging across grids
+ * is required to distribute data and perform global actions.
+ * In pseudo-UML, it looks like:
+ *
+ *                       Main                 Thread1
+ *                        .                      .
+ *                        .                      .
+ *                     +-----+                   .
+ *                     | AM  |                   .
+ *                     +--+--+                   .
+ *      +-------+         |                      .
+ *      | Main  |      +--+--+                   .
+ *      |       |      | SRE |---.               .
+ *      | Stats |      +-----+    \              .
+ *      |       |         |        \  (uuid)  +-----+
+ *      | Coll. |      +--+--+      `-------->| SR  |
+ *      +-------+      | MSC |                +--+--+
+ *         | ^         +-----+                   |
+ *         | |  (uuid)  / .                   +-----+ (uuid)
+ *         |  `--------'  .                   | MSC |---------.
+ *         |              .                   +-----+         |
+ *         |           +-----+                   .            v
+ *         |           | TE  |                   .        +-------+
+ *         |           +--+--+                   .        | Thd1  |
+ *         |              |                      .        |       |
+ *         |  (llsd)   +-----+                   .        | Stats |
+ *          `--------->| RSC |                   .        |       |
+ *                     +--+--+                   .        | Coll. |
+ *                        |                      .        +-------+
+ *                     +--+--+                   .            |
+ *                     | SME |---.               .            |
+ *                     +-----+    \              .            |
+ *                        .        \ (llsd)   +-----+         |
+ *                        .         `-------->| SM  |         |
+ *                        .                   +--+--+         |
+ *                        .                      |            |
+ *                        .                   +-----+  (llsd) |
+ *                        .                   | RSC |<--------'
+ *                        .                   +-----+
+ *                        .                      |
+ *                        .                   +-----+
+ *                        .                   | CP  |--> HTTP PUT
+ *                        .                   +-----+
+ *                        .                      .
+ *                        .                      .
+ *
+ *
+ * Key:
+ *
+ * SRE - Set Region Enqueued.  Enqueue a 'Set Region' command in
+ *       the other thread providing the new UUID of the region.
+ *       TFReqSetRegion carries the data.
+ * SR  - Set Region.  New region UUID is sent to the thread-local
+ *       collector.
+ * SME - Send Metrics Enqueued.  Enqueue a 'Send Metrics' command
+ *       including an ownership transfer of an LLSD.
+ *       TFReqSendMetrics carries the data.
+ * SM  - Send Metrics.  Global metrics reporting operation.  Takes
+ *       the remote LLSD from the command, merges it with and LLSD
+ *       from the local collector and sends it to the grid.
+ * AM  - Agent Moved.  Agent has completed some sort of move to a
+ *       new region.
+ * TE  - Timer Expired.  Metrics timer has expired (on the order
+ *       of 10 minutes).
+ * CP  - CURL Put
+ * MSC - Modify Stats Collector.  State change in the thread-local
+ *       collector.  Typically a region change which affects the
+ *       global pointers used to find the 'current stats'.
+ * RSC - Read Stats Collector.  Extract collector data in LLSD form.
+ *
+ */
+class TFRequest // : public LLQueuedThread::QueuedRequest
+{
+public:
+	// Default ctors and assignment operator are correct.
+
+	virtual ~TFRequest()
+		{}
+
+	virtual bool doWork(LLTextureFetchWorker * worker) = 0;
+};
+
+
+/**
+ * @brief Implements a 'Set Region' cross-thread command.
+ *
+ * When an agent moves to a new region, subsequent metrics need
+ * to be binned into a new or existing stats collection in 1:1
+ * relationship with the region.  We communicate this region
+ * change across the threads involved in the communication with
+ * this message.
+ *
+ * Corresponds to LLTextureFetch::commandSetRegion()
+ */
+class TFReqSetRegion : public TFRequest
+{
+public:
+	TFReqSetRegion(const LLUUID & region_id)
+		: TFRequest(),
+		  mRegionID(region_id)
+		{}
+	TFReqSetRegion & operator=(const TFReqSetRegion &);	// Not defined
+
+	virtual ~TFReqSetRegion()
+		{}
+
+	virtual bool doWork(LLTextureFetchWorker * worker);
+		
+public:
+	const LLUUID mRegionID;
+};
+
+
+/**
+ * @brief Implements a 'Send Metrics' cross-thread command.
+ *
+ * This is the big operation.  The main thread gathers metrics
+ * for a period of minutes into LLViewerAssetStats and other
+ * objects then builds an LLSD to represent the data.  It uses
+ * this command to transfer the LLSD, content *and* ownership,
+ * to the TextureFetch thread which adds its own metrics and
+ * kicks of an HTTP POST of the resulting data to the currently
+ * active metrics collector.
+ *
+ * Corresponds to LLTextureFetch::commandSendMetrics()
+ */
+class TFReqSendMetrics : public TFRequest
+{
+public:
+    /**
+	 * Construct the 'Send Metrics' command to have the TextureFetch
+	 * thread add and log metrics data.
+	 *
+	 * @param	caps_url		URL of a "ViewerMetrics" Caps target
+	 *							to receive the data.  Does not have to
+	 *							be associated with a particular region.
+	 *
+	 * @param	report_main		Pointer to LLSD containing main
+	 *							thread metrics.  Ownership transfers
+	 *							to the new thread using very carefully
+	 *							constructed code.
+	 */
+	TFReqSendMetrics(const std::string & caps_url,
+					 LLSD * report_main)
+		: TFRequest(),
+		  mCapsURL(caps_url),
+		  mReportMain(report_main)
+		{}
+	TFReqSendMetrics & operator=(const TFReqSendMetrics &);	// Not defined
+
+	virtual ~TFReqSendMetrics();
+
+	virtual bool doWork(LLTextureFetchWorker * worker);
+		
+public:
+	const std::string mCapsURL;
+	LLSD * mReportMain;
+};
+
+} // end of anonymous namespace
+
+
 //////////////////////////////////////////////////////////////////////////////
 
 //static
@@ -374,6 +586,9 @@ const char* LLTextureFetchWorker::sStateDescs[] = {
 	"DONE",
 };
 
+// static
+volatile bool LLTextureFetch::svMetricsDataBreak(true);	// Start with a data break
+
 // called from MAIN THREAD
 
 LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
@@ -423,7 +638,8 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
 	  mFirstPacket(0),
 	  mLastPacket(-1),
 	  mTotalPackets(0),
-	  mImageCodec(IMG_CODEC_INVALID)
+	  mImageCodec(IMG_CODEC_INVALID),
+	  mMetricsStartTime(0)
 {
 	mCanUseNET = mUrl.empty() ;
 
@@ -591,6 +807,10 @@ bool LLTextureFetchWorker::doWork(S32 param)
 			return true; // abort
 		}
 	}
+
+	// Run a cross-thread command, if any.
+	mFetcher->cmdDoWork(this);
+	
 	if(mImagePriority < F_ALMOST_ZERO)
 	{
 		if (mState == INIT || mState == LOAD_FROM_NETWORK || mState == LOAD_FROM_SIMULATOR)
@@ -800,7 +1020,15 @@ bool LLTextureFetchWorker::doWork(S32 param)
 			mRequestedDiscard = mDesiredDiscard;
 			mSentRequest = QUEUED;
 			mFetcher->addToNetworkQueue(this);
+			if (! mMetricsStartTime)
+			{
+				mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
+			}
+			LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE,
+														 false,
+														 LLImageBase::TYPE_AVATAR_BAKE == mType);
 			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
+			
 			return false;
 		}
 		else
@@ -809,6 +1037,12 @@ bool LLTextureFetchWorker::doWork(S32 param)
 			//llassert_always(mFetcher->mNetworkQueue.find(mID) != mFetcher->mNetworkQueue.end());
 			// Make certain this is in the network queue
 			//mFetcher->addToNetworkQueue(this);
+			//if (! mMetricsStartTime)
+			//{
+			//   mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
+			//}
+			//LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE, false,
+			//                                             LLImageBase::TYPE_AVATAR_BAKE == mType);
 			//setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
 			return false;
 		}
@@ -832,11 +1066,30 @@ bool LLTextureFetchWorker::doWork(S32 param)
 			}
 			setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
 			mState = DECODE_IMAGE;
-			mWriteToCacheState = SHOULD_WRITE ;
+			mWriteToCacheState = SHOULD_WRITE;
+
+			if (mMetricsStartTime)
+			{
+				LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE,
+															  false,
+															  LLImageBase::TYPE_AVATAR_BAKE == mType,
+															  LLViewerAssetStatsFF::get_timestamp() - mMetricsStartTime);
+				mMetricsStartTime = 0;
+			}
+			LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE,
+														 false,
+														 LLImageBase::TYPE_AVATAR_BAKE == mType);
 		}
 		else
 		{
 			mFetcher->addToNetworkQueue(this); // failsafe
+			if (! mMetricsStartTime)
+			{
+				mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
+			}
+			LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE,
+														 false,
+														 LLImageBase::TYPE_AVATAR_BAKE == mType);
 			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
 		}
 		return false;
@@ -898,6 +1151,14 @@ bool LLTextureFetchWorker::doWork(S32 param)
 				mState = WAIT_HTTP_REQ;	
 
 				mFetcher->addToHTTPQueue(mID);
+				if (! mMetricsStartTime)
+				{
+					mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
+				}
+				LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE,
+															 true,
+															 LLImageBase::TYPE_AVATAR_BAKE == mType);
+
 				// Will call callbackHttpGet when curl request completes
 				std::vector<std::string> headers;
 				headers.push_back("Accept: image/x-j2c");
@@ -1534,6 +1795,12 @@ LLTextureFetch::~LLTextureFetch()
 {
 	clearDeleteList() ;
 
+	while (! mCommands.empty())
+	{
+		delete mCommands.front();
+		mCommands.erase(mCommands.begin());
+	}
+	
 	// ~LLQueuedThread() called here
 }
 
@@ -1815,6 +2082,25 @@ bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority)
 	return res;
 }
 
+// virtual
+bool LLTextureFetch::runCondition()
+{
+	// Caller is holding the lock on LLThread's condition variable.
+	
+	// LLQueuedThread, unlike its base class LLThread, makes this a
+	// private method which is unfortunate.  I want to use it directly
+	// but I'm going to have to re-implement the logic here (or change
+	// declarations, which I don't want to do right now).
+
+	bool have_no_commands(false);
+	{
+		LLMutexLock lock(&mQueueMutex);
+		
+		have_no_commands = mCommands.empty();
+	}
+	return ! (have_no_commands && mRequestQueue.empty() && mIdleThread);
+}
+
 //////////////////////////////////////////////////////////////////////////////
 
 // MAIN THREAD
@@ -2357,3 +2643,195 @@ void LLTextureFetch::dump()
 	}
 }
 
+//////////////////////////////////////////////////////////////////////////////
+
+// cross-thread command methods
+
+void LLTextureFetch::commandSetRegion(const LLUUID & region_id)
+{
+	TFReqSetRegion * req = new TFReqSetRegion(region_id);
+
+	cmdEnqueue(req);
+}
+
+void LLTextureFetch::commandSendMetrics(const std::string & caps_url,
+										LLSD * report_main)
+{
+	TFReqSendMetrics * req = new TFReqSendMetrics(caps_url, report_main);
+
+	cmdEnqueue(req);
+}
+
+void LLTextureFetch::commandDataBreak()
+{
+	// The pedantically correct way to implement this is to create a command
+	// request object in the above fashion and enqueue it.  However, this is
+	// simple data of an advisorial not operational nature and this case
+	// of shared-write access is tolerable.
+
+	LLTextureFetch::svMetricsDataBreak = true;
+}
+
+void LLTextureFetch::cmdEnqueue(TFRequest * req)
+{
+	lockQueue();
+	mCommands.push_back(req);
+	wake();
+	unlockQueue();
+}
+
+TFRequest * LLTextureFetch::cmdDequeue()
+{
+	TFRequest * ret = 0;
+	
+	lockQueue();
+	if (! mCommands.empty())
+	{
+		ret = mCommands.front();
+		mCommands.erase(mCommands.begin());
+	}
+	unlockQueue();
+
+	return ret;
+}
+
+void LLTextureFetch::cmdDoWork(LLTextureFetchWorker * worker)
+{
+	// Queue is expected to be locked here.
+
+	if (mDebugPause)
+	{
+		return;  // debug: don't do any work
+	}
+
+	TFRequest * req = cmdDequeue();
+	if (req)
+	{
+		// One request per pass should really be enough for this.
+		req->doWork(worker);
+		delete req;
+	}
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+// Private (anonymous) class methods implementing the command scheme.
+
+namespace
+{
+
+/**
+ * Implements the 'Set Region' command.
+ *
+ * Thread:  Thread1 (TextureFetch)
+ */
+bool
+TFReqSetRegion::doWork(LLTextureFetchWorker *)
+{
+	LLViewerAssetStatsFF::set_region_thread1(mRegionID);
+
+	return true;
+}
+
+
+TFReqSendMetrics::~TFReqSendMetrics()
+{
+	delete mReportMain;
+	mReportMain = 0;
+}
+
+
+/**
+ * Implements the 'Send Metrics' command.  Takes over
+ * ownership of the passed LLSD pointer.
+ *
+ * Thread:  Thread1 (TextureFetch)
+ */
+bool
+TFReqSendMetrics::doWork(LLTextureFetchWorker * fetch_worker)
+{
+	/*
+	 * HTTP POST responder.  Doesn't do much but tries to
+	 * detect simple breaks in recording the metrics stream.
+	 *
+	 * The 'volatile' modifiers don't indicate signals,
+	 * mmap'd memory or threads, really.  They indicate that
+	 * the referenced data is part of a pseudo-closure for
+	 * this responder rather than being required for correct
+	 * operation.
+	 */
+	class lcl_responder : public LLCurl::Responder
+	{
+	public:
+		lcl_responder(volatile bool & post_failed,
+					  volatile bool & post_succeeded)
+			: LLHTTPClient::Responder(),
+			  mPostFailedStatus(post_failed),
+			  mPostSucceededStatus(post_succeeded)
+			{}
+
+		// virtual
+		void error(U32 status_num, const std::string & reason)
+			{
+				mPostFailedStatus = true;
+			}
+
+		// virtual
+		void result(const LLSD & content)
+			{
+				mPostSucceededStatus = true;
+			}
+
+	private:
+		volatile bool & mPostFailedStatus;
+		volatile bool & mPostSucceededStatus;
+	};
+	
+	if (! gViewerAssetStatsThread1)
+		return true;
+
+	if (! mCapsURL.empty())
+	{
+		static volatile bool not_initial_report(false);
+		static S32 report_sequence(0);
+
+		// We've already taken over ownership of the LLSD at this point
+		// and can do normal LLSD sharing operations at this point.  But
+		// still being careful, regardless.
+		LLSD & envelope = *mReportMain;
+		{
+			envelope["sequence"] = report_sequence;
+			envelope["regions_alt"] = gViewerAssetStatsThread1->asLLSD();
+			envelope["initial"] = ! not_initial_report;					// Initial data from viewer
+			envelope["break"] = LLTextureFetch::svMetricsDataBreak;		// Break in data prior to this report
+
+			// *FIXME:  Need to merge the two metrics streams here....
+		}
+
+		// Update sequence number and other metadata for next attempt.
+		if (S32_MAX == ++report_sequence)
+			report_sequence = 0;
+		LLTextureFetch::svMetricsDataBreak = false;
+
+		LLCurlRequest::headers_t headers;
+		fetch_worker->getFetcher().getCurlRequest().post(mCapsURL,
+														 headers,
+														 envelope,
+														 new lcl_responder(LLTextureFetch::svMetricsDataBreak,
+																		   not_initial_report));
+	}
+	else
+	{
+		LLTextureFetch::svMetricsDataBreak = true;
+	}
+
+	gViewerAssetStatsThread1->reset();
+
+	return true;
+}
+
+} // end of anonymous namespace
+
+
+
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index 796109df06..220305d881 100644
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -40,6 +40,7 @@ class HTTPGetResponder;
 class LLTextureCache;
 class LLImageDecodeThread;
 class LLHost;
+namespace { class TFRequest; }
 
 // Interface class
 class LLTextureFetch : public LLWorkerThread
@@ -83,6 +84,13 @@ public:
 	LLTextureFetchWorker* getWorkerAfterLock(const LLUUID& id);
 
 	LLTextureInfo* getTextureInfo() { return &mTextureInfo; }
+
+	// Commands available to other threads.
+	void commandSetRegion(const LLUUID & region_id);
+	void commandSendMetrics(const std::string & caps_url, LLSD * report_main);
+	void commandDataBreak();
+
+	LLCurlRequest & getCurlRequest() { return *mCurlGetRequest; }
 	
 protected:
 	void addToNetworkQueue(LLTextureFetchWorker* worker);
@@ -91,7 +99,10 @@ protected:
 	void removeFromHTTPQueue(const LLUUID& id, S32 received_size = 0);
 	void removeRequest(LLTextureFetchWorker* worker, bool cancel);
 	// Called from worker thread (during doWork)
-	void processCurlRequests();	
+	void processCurlRequests();
+
+	// Overrides from the LLThread tree
+	bool runCondition();
 
 private:
 	void sendRequestListToSimulators();
@@ -99,6 +110,11 @@ private:
 	/*virtual*/ void endThread(void);
 	/*virtual*/ void threadedUpdate(void);
 
+	// command helpers
+	void cmdEnqueue(TFRequest *);
+	TFRequest * cmdDequeue();
+	void cmdDoWork(LLTextureFetchWorker* worker);
+	
 public:
 	LLUUID mDebugID;
 	S32 mDebugCount;
@@ -107,7 +123,7 @@ public:
 	S32 mBadPacketCount;
 	
 private:
-	LLMutex mQueueMutex;        //to protect mRequestMap only
+	LLMutex mQueueMutex;        //to protect mRequestMap and mCommands only
 	LLMutex mNetworkQueueMutex; //to protect mNetworkQueue, mHTTPTextureQueue and mCancelQueue.
 
 	LLTextureCache* mTextureCache;
@@ -129,6 +145,19 @@ private:
 	LLTextureInfo mTextureInfo;
 
 	U32 mHTTPTextureBits;
+
+	// Special cross-thread command queue.  This command queue
+	// is logically tied to LLQueuedThread's list of
+	// QueuedRequest instances and so must be covered by the
+	// same locks.
+	typedef std::vector<TFRequest *> command_queue_t;
+	command_queue_t mCommands;
+
+public:
+	// A probabilistically-correct indicator that the current
+	// attempt to log metrics follows a break in the metrics stream
+	// reporting due to either startup or a problem POSTing data.
+	static volatile bool svMetricsDataBreak;
 };
 
 #endif // LL_LLTEXTUREFETCH_H
diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp
index 37e7c43f36..09c0364f09 100644
--- a/indra/newview/llviewerassetstats.cpp
+++ b/indra/newview/llviewerassetstats.cpp
@@ -37,6 +37,35 @@
 #include "stdtypes.h"
 
 /*
+ * Classes and utility functions for per-thread and per-region
+ * asset and experiential metrics to be aggregated grid-wide.
+ *
+ * The basic metrics grouping is LLViewerAssetStats::PerRegionStats.
+ * This provides various counters and simple statistics for asset
+ * fetches binned into a few categories.  One of these is maintained
+ * for each region encountered and the 'current' region is available
+ * as a simple reference.  Each thread (presently two) interested
+ * in participating in these stats gets an instance of the
+ * LLViewerAssetStats class so that threads are completely
+ * independent.
+ *
+ * The idea of a current region is used for simplicity and speed
+ * of categorization.  Each metrics event could have taken a
+ * region uuid argument resulting in a suitable lookup.  Arguments
+ * against this design include:
+ *
+ *  -  Region uuid not trivially available to caller.
+ *  -  Cost (cpu, disruption in real work flow) too high.
+ *  -  Additional precision not really meaningful.
+ *
+ * By itself, the LLViewerAssetStats class is thread- and
+ * viewer-agnostic and can be used anywhere without assumptions
+ * of global pointers and other context.  For the viewer,
+ * a set of free functions are provided in the namespace
+ * LLViewerAssetStatsFF which *do* implement viewer-native
+ * policies about per-thread globals and will do correct
+ * defensive tests of same.
+ *
  * References
  *
  * Project:
@@ -103,7 +132,7 @@ LLViewerAssetStats::reset()
 	mRegionStats.clear();
 
 	// If we have a current stats, reset it, otherwise, as at construction,
-	// create a new one.
+	// create a new one as we must always have a current stats block.
 	if (mCurRegionStats)
 	{
 		mCurRegionStats->reset();
@@ -130,7 +159,7 @@ LLViewerAssetStats::setRegionID(const LLUUID & region_id)
 	PerRegionContainer::iterator new_stats = mRegionStats.find(region_id);
 	if (mRegionStats.end() == new_stats)
 	{
-		// Haven't seen this region_id before, create a new block make it current.
+		// Haven't seen this region_id before, create a new block and make it current.
 		mCurRegionStats = new PerRegionStats(region_id);
 		mRegionStats[region_id] = mCurRegionStats;
 	}
@@ -159,7 +188,7 @@ LLViewerAssetStats::recordGetDequeued(LLViewerAssetType::EType at, bool with_htt
 }
 
 void
-LLViewerAssetStats::recordGetServiced(LLViewerAssetType::EType at, bool with_http, bool is_temp, F64 duration)
+LLViewerAssetStats::recordGetServiced(LLViewerAssetType::EType at, bool with_http, bool is_temp, duration_t duration)
 {
 	const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp));
 
@@ -213,9 +242,9 @@ LLViewerAssetStats::asLLSD() const
 			slot[enq_tag] = LLSD(S32(stats.mRequests[i].mEnqueued.getCount()));
 			slot[deq_tag] = LLSD(S32(stats.mRequests[i].mDequeued.getCount()));
 			slot[rcnt_tag] = LLSD(S32(stats.mRequests[i].mResponse.getCount()));
-			slot[rmin_tag] = LLSD(stats.mRequests[i].mResponse.getMin());
-			slot[rmax_tag] = LLSD(stats.mRequests[i].mResponse.getMax());
-			slot[rmean_tag] = LLSD(stats.mRequests[i].mResponse.getMean());
+			slot[rmin_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMin()));
+			slot[rmax_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMax()));
+			slot[rmean_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMean()));
 		}
 
 		ret[it->first.asString()] = reg_stat;
@@ -231,9 +260,24 @@ LLViewerAssetStats::asLLSD() const
 namespace LLViewerAssetStatsFF
 {
 
+//
 // Target thread is elaborated in the function name.  This could
 // have been something 'templatey' like specializations iterated
 // over a set of constants but with so few, this is clearer I think.
+//
+// As for the threads themselves... rather than do fine-grained
+// locking as we gather statistics, this code creates a collector
+// for each thread, allocated and run independently.  Logging
+// happens at relatively infrequent intervals and at that time
+// the data is sent to a single thread to be aggregated into
+// a single entity with locks, thread safety and other niceties.
+//
+// A particularly fussy implementation would distribute the
+// per-thread pointers across separate cache lines.  But that should
+// be beyond current requirements.
+//
+
+// 'main' thread - initial program thread
 
 void
 set_region_main(const LLUUID & region_id)
@@ -263,7 +307,7 @@ record_dequeue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp)
 }
 
 void
-record_response_main(LLViewerAssetType::EType at, bool with_http, bool is_temp, F64 duration)
+record_response_main(LLViewerAssetType::EType at, bool with_http, bool is_temp, LLViewerAssetStats::duration_t duration)
 {
 	if (! gViewerAssetStatsMain)
 		return;
@@ -272,6 +316,8 @@ record_response_main(LLViewerAssetType::EType at, bool with_http, bool is_temp,
 }
 
 
+// 'thread1' - should be for TextureFetch thread
+
 void
 set_region_thread1(const LLUUID & region_id)
 {
@@ -300,7 +346,7 @@ record_dequeue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp
 }
 
 void
-record_response_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp, F64 duration)
+record_response_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp, LLViewerAssetStats::duration_t duration)
 {
 	if (! gViewerAssetStatsThread1)
 		return;
@@ -308,6 +354,31 @@ record_response_thread1(LLViewerAssetType::EType at, bool with_http, bool is_tem
 	gViewerAssetStatsThread1->recordGetServiced(at, with_http, is_temp, duration);
 }
 
+
+void
+init()
+{
+	if (! gViewerAssetStatsMain)
+	{
+		gViewerAssetStatsMain = new LLViewerAssetStats;
+	}
+	if (! gViewerAssetStatsThread1)
+	{
+		gViewerAssetStatsThread1 = new LLViewerAssetStats;
+	}
+}
+
+void
+cleanup()
+{
+	delete gViewerAssetStatsMain;
+	gViewerAssetStatsMain = 0;
+
+	delete gViewerAssetStatsThread1;
+	gViewerAssetStatsThread1 = 0;
+}
+	
+
 } // namespace LLViewerAssetStatsFF
 
 
diff --git a/indra/newview/llviewerassetstats.h b/indra/newview/llviewerassetstats.h
index b8356a5ff5..efd0897bb8 100644
--- a/indra/newview/llviewerassetstats.h
+++ b/indra/newview/llviewerassetstats.h
@@ -95,6 +95,13 @@ public:
 		EVACCount						// Must be last
 	};
 
+	/**
+	 * Type for duration and other time values in the metrics.  Selected
+	 * for compatibility with the pre-existing timestamp on the texture
+	 * fetcher class, LLTextureFetch.
+	 */
+	typedef U64 duration_t;
+	
 	/**
 	 * Collected data for a single region visited by the avatar.
 	 */
@@ -107,6 +114,7 @@ public:
 			{
 				reset();
 			}
+		// Default assignment and destructor are correct.
 		
 		void reset();
 
@@ -114,9 +122,9 @@ public:
 		LLUUID mRegionID;
 		struct
 		{
-			LLSimpleStatCounter		mEnqueued;
-			LLSimpleStatCounter		mDequeued;
-			LLSimpleStatMMM<>		mResponse;
+			LLSimpleStatCounter			mEnqueued;
+			LLSimpleStatCounter			mDequeued;
+			LLSimpleStatMMM<duration_t>	mResponse;
 		} mRequests [EVACCount];
 	};
 
@@ -137,7 +145,7 @@ public:
 	// Non-Cached GET Requests
 	void recordGetEnqueued(LLViewerAssetType::EType at, bool with_http, bool is_temp);
 	void recordGetDequeued(LLViewerAssetType::EType at, bool with_http, bool is_temp);
-	void recordGetServiced(LLViewerAssetType::EType at, bool with_http, bool is_temp, F64 duration);
+	void recordGetServiced(LLViewerAssetType::EType at, bool with_http, bool is_temp, duration_t duration);
 
 	// Retrieve current metrics for all visited regions.
 	const LLSD asLLSD() const;
@@ -180,23 +188,51 @@ extern LLViewerAssetStats * gViewerAssetStatsThread1;
 
 namespace LLViewerAssetStatsFF
 {
+/**
+ * We have many timers, clocks etc. in the runtime.  This is the
+ * canonical timestamp for these metrics which is compatible with
+ * the pre-existing timestamping in the texture fetcher.
+ */
+inline LLViewerAssetStats::duration_t get_timestamp()
+{
+	return LLTimer::getTotalTime();
+}
 
+/**
+ * Region context, event and duration loggers for the Main thread.
+ */
 void set_region_main(const LLUUID & region_id);
 
 void record_enqueue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp);
 
 void record_dequeue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp);
 
-void record_response_main(LLViewerAssetType::EType at, bool with_http, bool is_temp, F64 duration);
+void record_response_main(LLViewerAssetType::EType at, bool with_http, bool is_temp,
+						  LLViewerAssetStats::duration_t duration);
 
 
+/**
+ * Region context, event and duration loggers for Thread 1.
+ */
 void set_region_thread1(const LLUUID & region_id);
 
 void record_enqueue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp);
 
 void record_dequeue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp);
 
-void record_response_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp, F64 duration);
+void record_response_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp,
+						  LLViewerAssetStats::duration_t duration);
+
+/**
+ * @brief Allocation and deallocation of globals.
+ *
+ * init() should be called before threads are started that will access it though
+ * you'll likely get away with calling it afterwards.  cleanup() should only be
+ * called after threads are shutdown to prevent races on the global pointers.
+ */
+void init();
+
+void cleanup();
 
 } // namespace LLViewerAssetStatsFF
 
diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp
index 2e7ef0fec3..197cb3468c 100644
--- a/indra/newview/llviewerassetstorage.cpp
+++ b/indra/newview/llviewerassetstorage.cpp
@@ -33,6 +33,61 @@
 #include "message.h"
 
 #include "llagent.h"
+#include "lltransfersourceasset.h"
+#include "lltransfertargetvfile.h"
+#include "llviewerassetstats.h"
+
+///----------------------------------------------------------------------------
+/// LLViewerAssetRequest
+///----------------------------------------------------------------------------
+
+/**
+ * @brief Local class to encapsulate asset fetch requests with a timestamp.
+ *
+ * Derived from the common LLAssetRequest class, this is currently used
+ * only for fetch/get operations and its only function is to wrap remote
+ * asset fetch requests so that they can be timed.
+ */
+class LLViewerAssetRequest : public LLAssetRequest
+{
+public:
+	LLViewerAssetRequest(const LLUUID &uuid, const LLAssetType::EType type)
+		: LLAssetRequest(uuid, type),
+		  mMetricsStartTime(0)
+		{
+		}
+	
+	LLViewerAssetRequest & operator=(const LLViewerAssetRequest &);	// Not defined
+	// Default assignment operator valid
+	
+	// virtual
+	~LLViewerAssetRequest()
+		{
+			recordMetrics();
+		}
+
+protected:
+	void recordMetrics()
+		{
+			if (mMetricsStartTime)
+			{
+				// Okay, it appears this request was used for useful things.  Record
+				// the expected dequeue and duration of request processing.
+				LLViewerAssetStatsFF::record_dequeue_main(mType, false, false);
+				LLViewerAssetStatsFF::record_response_main(mType, false, false,
+														   (LLViewerAssetStatsFF::get_timestamp()
+															- mMetricsStartTime));
+				mMetricsStartTime = 0;
+			}
+		}
+	
+public:
+	LLViewerAssetStats::duration_t		mMetricsStartTime;
+};
+
+///----------------------------------------------------------------------------
+/// LLViewerAssetStorage
+///----------------------------------------------------------------------------
 
 LLViewerAssetStorage::LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer,
 										   LLVFS *vfs, LLVFS *static_vfs, 
@@ -258,3 +313,72 @@ void LLViewerAssetStorage::storeAssetData(
 		}
 	}
 }
+
+
+/**
+ * @brief Allocate and queue an asset fetch request for the viewer
+ *
+ * This is a nearly-verbatim copy of the base class's implementation
+ * with the following changes:
+ *  -  Use a locally-derived request class
+ *  -  Start timing for metrics when request is queued
+ *
+ * This is an unfortunate implementation choice but it's forced by
+ * current conditions.  A refactoring that might clean up the layers
+ * of responsibility or introduce factories or more virtualization
+ * of methods would enable a more attractive solution.
+ *
+ * If LLAssetStorage::_queueDataRequest changes, this must change
+ * as well.
+ */
+
+// virtual
+void LLViewerAssetStorage::_queueDataRequest(
+	const LLUUID& uuid,
+	LLAssetType::EType atype,
+	LLGetAssetCallback callback,
+	void *user_data,
+	BOOL duplicate,
+	BOOL is_priority)
+{
+	if (mUpstreamHost.isOk())
+	{
+		// stash the callback info so we can find it after we get the response message
+		LLViewerAssetRequest *req = new LLViewerAssetRequest(uuid, atype);
+		req->mDownCallback = callback;
+		req->mUserData = user_data;
+		req->mIsPriority = is_priority;
+		req->mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
+		
+		mPendingDownloads.push_back(req);
+	
+		if (!duplicate)
+		{
+			// send request message to our upstream data provider
+			// Create a new asset transfer.
+			LLTransferSourceParamsAsset spa;
+			spa.setAsset(uuid, atype);
+
+			// Set our destination file, and the completion callback.
+			LLTransferTargetParamsVFile tpvf;
+			tpvf.setAsset(uuid, atype);
+			tpvf.setCallback(downloadCompleteCallback, req);
+
+			llinfos << "Starting transfer for " << uuid << llendl;
+			LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(mUpstreamHost, LLTCT_ASSET);
+			ttcp->requestTransfer(spa, tpvf, 100.f + (is_priority ? 1.f : 0.f));
+
+			LLViewerAssetStatsFF::record_enqueue_main(atype, false, false);
+		}
+	}
+	else
+	{
+		// uh-oh, we shouldn't have gotten here
+		llwarns << "Attempt to move asset data request upstream w/o valid upstream provider" << llendl;
+		if (callback)
+		{
+			callback(mVFS, uuid, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM);
+		}
+	}
+}
+
diff --git a/indra/newview/llviewerassetstorage.h b/indra/newview/llviewerassetstorage.h
index 6346b79f03..ca9b9943fa 100644
--- a/indra/newview/llviewerassetstorage.h
+++ b/indra/newview/llviewerassetstorage.h
@@ -63,6 +63,17 @@ public:
 		bool is_priority = false,
 		bool user_waiting=FALSE,
 		F64 timeout=LL_ASSET_STORAGE_TIMEOUT);
+
+protected:
+	using LLAssetStorage::_queueDataRequest;
+
+	// virtual
+	void _queueDataRequest(const LLUUID& uuid,
+						   LLAssetType::EType type,
+						   void (*callback) (LLVFS *vfs, const LLUUID&, LLAssetType::EType, void *, S32, LLExtStat),
+						   void *user_data,
+						   BOOL duplicate,
+						   BOOL is_priority);
 };
 
 #endif
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 98f16757b2..79b45a459f 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -1403,6 +1403,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
 	capabilityNames.append("UpdateNotecardTaskInventory");
 	capabilityNames.append("UpdateScriptTask");
 	capabilityNames.append("UploadBakedTexture");
+	capabilityNames.append("ViewerMetrics");
 	capabilityNames.append("ViewerStartAuction");
 	capabilityNames.append("ViewerStats");
 	capabilityNames.append("WebFetchInventoryDescendents");
diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp
index affe16c177..c3c38ef925 100644
--- a/indra/newview/tests/llviewerassetstats_test.cpp
+++ b/indra/newview/tests/llviewerassetstats_test.cpp
@@ -114,7 +114,7 @@ namespace tut
 
 		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false);
 
-		LLViewerAssetStatsFF::record_response_main(LLViewerAssetType::AT_GESTURE, false, false, 12.3);
+		LLViewerAssetStatsFF::record_response_main(LLViewerAssetType::AT_GESTURE, false, false, 12300000ULL);
 	}
 
 	// Create a non-global instance and check the structure
-- 
cgit v1.2.3


From a99db82e9b3ce25bf2745721b57f0259a770b26a Mon Sep 17 00:00:00 2001
From: Monty Brandenberg <monty@lindenlab.com>
Date: Fri, 19 Nov 2010 15:14:40 -0800
Subject: ESC-155 Multi-threaded umbrella collector for stats aggregation Code
 complete with the intelligence to merge counts, mins, maxes and means with
 reasonable defences.  Added QAMode controls to the viewer so that we can QA
 this more quickly by reducing the timing interval and sending the metrics
 body to local logging as well as to the caps service.

---
 indra/newview/llappviewer.cpp                   |  21 +-
 indra/newview/lltexturefetch.cpp                |  67 ++++---
 indra/newview/llviewerassetstats.cpp            | 248 +++++++++++++++++++++++-
 indra/newview/llviewerassetstats.h              |  60 ++++--
 indra/newview/tests/llviewerassetstats_test.cpp | 134 ++++++++++---
 5 files changed, 443 insertions(+), 87 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 2e056238e4..e696e1af84 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -336,10 +336,9 @@ LLAppViewer::LLUpdaterInfo *LLAppViewer::sUpdaterInfo = NULL ;
 //----------------------------------------------------------------------------
 // Metrics logging control constants
 //----------------------------------------------------------------------------
-static const F32 METRICS_INTERVAL_MIN = 300.0;
-static const F32 METRICS_INTERVAL_MAX = 3600.0;
 static const F32 METRICS_INTERVAL_DEFAULT = 600.0;
-
+static const F32 METRICS_INTERVAL_QA = 30.0;
+static F32 app_metrics_interval = METRICS_INTERVAL_DEFAULT;
 
 void idle_afk_check()
 {
@@ -664,8 +663,15 @@ bool LLAppViewer::init()
     // Called before threads are created.
     LLCurl::initClass();
     LLMachineID::init();
-
-	LLViewerAssetStatsFF::init();
+	
+	{
+		// Viewer metrics initialization
+		if (gSavedSettings.getBOOL("QAMode") && gSavedSettings.getBOOL("QAModeMetricsSubmode"))
+		{
+			app_metrics_interval = METRICS_INTERVAL_QA;
+		}
+		LLViewerAssetStatsFF::init();
+	}
 
     initThreads();
     writeSystemInfo();
@@ -3701,7 +3707,7 @@ void LLAppViewer::idle()
 		static LLTimer report_interval;
 
 		// *TODO:  Add configuration controls for this
-		if (report_interval.getElapsedTimeF32() >= METRICS_INTERVAL_DEFAULT)
+		if (report_interval.getElapsedTimeF32() >= app_metrics_interval)
 		{
 			metricsIdle(! gDisconnected);
 			report_interval.reset();
@@ -4595,7 +4601,6 @@ void LLAppViewer::metricsIdle(bool enable_reporting)
 	if (regionp)
 	{
 		caps_url = regionp->getCapability("ViewerMetrics");
-		caps_url = "http://localhost:80/putz/";
 	}
 	
 	if (enable_reporting && regionp && ! caps_url.empty())
@@ -4608,9 +4613,9 @@ void LLAppViewer::metricsIdle(bool enable_reporting)
 		
 		LLSD * envelope = new LLSD(LLSD::emptyMap());
 		{
+			(*envelope) = gViewerAssetStatsMain->asLLSD();
 			(*envelope)["session_id"] = gAgentSessionID;
 			(*envelope)["agent_id"] = gAgentID;
-			(*envelope)["regions"] = gViewerAssetStatsMain->asLLSD();
 		}
 		
 		if (LLAppViewer::sTextureFetch)
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index df99818ee9..d303d425c8 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -2764,68 +2764,77 @@ TFReqSendMetrics::doWork(LLTextureFetchWorker * fetch_worker)
 	class lcl_responder : public LLCurl::Responder
 	{
 	public:
-		lcl_responder(volatile bool & post_failed,
-					  volatile bool & post_succeeded)
+		lcl_responder(volatile bool & reporting_break,
+					  volatile bool & reporting_started)
 			: LLHTTPClient::Responder(),
-			  mPostFailedStatus(post_failed),
-			  mPostSucceededStatus(post_succeeded)
+			  mReportingBreak(reporting_break),
+			  mReportingStarted(reporting_started)
 			{}
 
 		// virtual
 		void error(U32 status_num, const std::string & reason)
 			{
-				mPostFailedStatus = true;
+				mReportingBreak = true;
 			}
 
 		// virtual
 		void result(const LLSD & content)
 			{
-				mPostSucceededStatus = true;
+				mReportingBreak = false;
+				mReportingStarted = true;
 			}
 
 	private:
-		volatile bool & mPostFailedStatus;
-		volatile bool & mPostSucceededStatus;
+		volatile bool & mReportingBreak;
+		volatile bool & mReportingStarted;
 	};
 	
 	if (! gViewerAssetStatsThread1)
 		return true;
 
-	if (! mCapsURL.empty())
-	{
-		static volatile bool not_initial_report(false);
-		static S32 report_sequence(0);
+	static volatile bool reporting_started(false);
+	static S32 report_sequence(0);
 
-		// We've already taken over ownership of the LLSD at this point
-		// and can do normal LLSD sharing operations at this point.  But
-		// still being careful, regardless.
-		LLSD & envelope = *mReportMain;
-		{
-			envelope["sequence"] = report_sequence;
-			envelope["regions_alt"] = gViewerAssetStatsThread1->asLLSD();
-			envelope["initial"] = ! not_initial_report;					// Initial data from viewer
-			envelope["break"] = LLTextureFetch::svMetricsDataBreak;		// Break in data prior to this report
+	// We've already taken over ownership of the LLSD at this point
+	// and can do normal LLSD sharing operations at this point.  But
+	// still being careful, regardless.
+	LLSD & main_stats = *mReportMain;
 
-			// *FIXME:  Need to merge the two metrics streams here....
-		}
+	LLSD thread1_stats = gViewerAssetStatsThread1->asLLSD();			// 'duration' & 'regions' from here
+	thread1_stats["message"] = "ViewerAssetMetrics";
+	thread1_stats["sequence"] = report_sequence;
+	thread1_stats["initial"] = ! reporting_started;						// Initial data from viewer
+	thread1_stats["break"] = LLTextureFetch::svMetricsDataBreak;		// Break in data prior to this report
+		
+	// Update sequence number
+	if (S32_MAX == ++report_sequence)
+		report_sequence = 0;
+
+	// Merge the two LLSDs into a single report
+	LLViewerAssetStatsFF::merge_stats(main_stats, thread1_stats);
 
-		// Update sequence number and other metadata for next attempt.
-		if (S32_MAX == ++report_sequence)
-			report_sequence = 0;
-		LLTextureFetch::svMetricsDataBreak = false;
+	// *TODO:  Consider putting a report size limiter here.
 
+	if (! mCapsURL.empty())
+	{
 		LLCurlRequest::headers_t headers;
 		fetch_worker->getFetcher().getCurlRequest().post(mCapsURL,
 														 headers,
-														 envelope,
+														 thread1_stats,
 														 new lcl_responder(LLTextureFetch::svMetricsDataBreak,
-																		   not_initial_report));
+																		   reporting_started));
 	}
 	else
 	{
 		LLTextureFetch::svMetricsDataBreak = true;
 	}
 
+	// In QA mode, Metrics submode, log the result for ease of testing
+	if (gSavedSettings.getBOOL("QAMode") && gSavedSettings.getBOOL("QAModeMetricsSubmode"))
+	{
+		LL_INFOS("QAViewerMetrics") << thread1_stats << LL_ENDL;
+	}
+
 	gViewerAssetStatsThread1->reset();
 
 	return true;
diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp
index 09c0364f09..c0287863f6 100644
--- a/indra/newview/llviewerassetstats.cpp
+++ b/indra/newview/llviewerassetstats.cpp
@@ -113,6 +113,16 @@ LLViewerAssetStats::PerRegionStats::reset()
 		mRequests[i].mDequeued.reset();
 		mRequests[i].mResponse.reset();
 	}
+
+	mTotalTime = 0;
+	mStartTimestamp = LLViewerAssetStatsFF::get_timestamp();
+}
+
+void
+LLViewerAssetStats::PerRegionStats::accumulateTime(duration_t now)
+{
+	mTotalTime += (now - mStartTimestamp);
+	mStartTimestamp = now;
 }
 
 
@@ -144,6 +154,9 @@ LLViewerAssetStats::reset()
 
 	// And add reference to map
 	mRegionStats[mRegionID] = mCurRegionStats;
+
+	// Start timestamp consistent with per-region collector
+	mResetTimestamp = mCurRegionStats->mStartTimestamp;
 }
 
 
@@ -155,7 +168,12 @@ LLViewerAssetStats::setRegionID(const LLUUID & region_id)
 		// Already active, ignore.
 		return;
 	}
-	
+
+	// Get duration for current set
+	const duration_t now = LLViewerAssetStatsFF::get_timestamp();
+	mCurRegionStats->accumulateTime(now);
+
+	// Prepare new set
 	PerRegionContainer::iterator new_stats = mRegionStats.find(region_id);
 	if (mRegionStats.end() == new_stats)
 	{
@@ -167,6 +185,7 @@ LLViewerAssetStats::setRegionID(const LLUUID & region_id)
 	{
 		mCurRegionStats = new_stats->second;
 	}
+	mCurRegionStats->mStartTimestamp = now;
 	mRegionID = region_id;
 }
 
@@ -195,8 +214,8 @@ LLViewerAssetStats::recordGetServiced(LLViewerAssetType::EType at, bool with_htt
 	mCurRegionStats->mRequests[int(eac)].mResponse.record(duration);
 }
 
-const LLSD
-LLViewerAssetStats::asLLSD() const
+LLSD
+LLViewerAssetStats::asLLSD()
 {
 	// Top-level tags
 	static const LLSD::String tags[EVACCount] = 
@@ -211,17 +230,18 @@ LLViewerAssetStats::asLLSD() const
 			LLSD::String("get_other")
 		};
 
-	// Sub-tags
+	// Sub-tags.  If you add or delete from this list, mergeLLSD() must be updated.
 	static const LLSD::String enq_tag("enqueued");
 	static const LLSD::String deq_tag("dequeued");
 	static const LLSD::String rcnt_tag("resp_count");
 	static const LLSD::String rmin_tag("resp_min");
 	static const LLSD::String rmax_tag("resp_max");
 	static const LLSD::String rmean_tag("resp_mean");
-	
-	LLSD ret = LLSD::emptyMap();
 
-	for (PerRegionContainer::const_iterator it = mRegionStats.begin();
+	const duration_t now = LLViewerAssetStatsFF::get_timestamp();
+	LLSD regions = LLSD::emptyMap();
+
+	for (PerRegionContainer::iterator it = mRegionStats.begin();
 		 mRegionStats.end() != it;
 		 ++it)
 	{
@@ -231,7 +251,8 @@ LLViewerAssetStats::asLLSD() const
 			continue;
 		}
 
-		const PerRegionStats & stats = *it->second;
+		PerRegionStats & stats = *it->second;
+		stats.accumulateTime(now);
 		
 		LLSD reg_stat = LLSD::emptyMap();
 		
@@ -247,12 +268,185 @@ LLViewerAssetStats::asLLSD() const
 			slot[rmean_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMean()));
 		}
 
-		ret[it->first.asString()] = reg_stat;
+		reg_stat["duration"] = LLSD::Integer(stats.mTotalTime / 1000000);
+		
+		regions[it->first.asString()] = reg_stat;
 	}
 
+	LLSD ret = LLSD::emptyMap();
+	ret["regions"] = regions;
+	ret["duration"] = LLSD::Integer((now - mResetTimestamp) / 1000000);
+	
 	return ret;
 }
 
+/* static */ void
+LLViewerAssetStats::mergeLLSD(const LLSD & src, LLSD & dst)
+{
+	// Merge operator definitions
+	static const int MOP_ADD_INT(0);
+	static const int MOP_MIN_REAL(1);
+	static const int MOP_MAX_REAL(2);
+	static const int MOP_MEAN_REAL(3);	// Requires a 'mMergeOpArg' to weight the input terms
+
+	static const LLSD::String regions_key("regions");
+	static const LLSD::String root_key_list[] =
+		{
+			"duration",
+			regions_key
+		};
+	
+	static const struct
+		{
+			LLSD::String		mName;
+			int					mMergeOp;
+			LLSD::String		mMergeOpArg;
+		}
+	key_list[] =
+		{
+			// Order is important below.  We modify the data in-place and
+			// so operations like MOP_MEAN_REAL which need the "resp_count"
+			// value for weighting must be performed before "resp_count"
+			// is modified or the weight will be wrong.  Key list is
+			// defined in asLLSD() and must track it.
+
+			{ "resp_mean", MOP_MEAN_REAL, "resp_count" },
+			{ "enqueued", MOP_ADD_INT, "" },
+			{ "dequeued", MOP_ADD_INT, "" },
+			{ "resp_count", MOP_ADD_INT, "" },
+			{ "resp_min", MOP_MIN_REAL, "" },
+			{ "resp_max", MOP_MAX_REAL, "" }
+		};
+
+	// First normalized the root keys but remember if we need to do full merge
+	const bool needs_deep_merge(src.has(regions_key) && dst.has(regions_key));
+	
+	for (int root_index(0); root_index < LL_ARRAY_SIZE(root_key_list); ++root_index)
+	{
+		const LLSD::String & key_name(root_key_list[root_index]);
+						
+		if ((! src.has(key_name)) || dst.has(key_name))
+			continue;
+
+		// key present in source, not in dst here
+		dst[key_name] = src[key_name];
+	}
+
+	if (! needs_deep_merge)
+		return;
+
+	// Okay, had both src and dst 'regions' section, do the deep merge
+
+	const LLSD & root_src(src[regions_key]);
+	LLSD & root_dst(dst[regions_key]);
+	
+	const LLSD::map_const_iterator it_end(root_src.endMap());
+	for (LLSD::map_const_iterator it(root_src.beginMap()); it_end != it; ++it)
+	{
+		if (! root_dst.has(it->first))
+		{
+			// src[<region>] without matching dst[<region>]
+			root_dst[it->first] = it->second;
+		}
+		else
+		{
+			// src[<region>] with matching dst[<region>]
+			// We have matching source and destination regions.
+			// Now iterate over each asset bin in the region status.  Could iterate over
+			// an explicit list but this will do as well.
+			LLSD & reg_dst(root_dst[it->first]);
+			const LLSD & reg_src(root_src[it->first]);
+
+			const LLSD::map_const_iterator it_src_bin_end(reg_src.endMap());
+			for (LLSD::map_const_iterator it_src_bin(reg_src.beginMap()); it_src_bin_end != it_src_bin; ++it_src_bin)
+			{
+				static const LLSD::String no_touch_1("duration");
+
+				if (no_touch_1 == it_src_bin->first)
+				{
+					continue;
+				}
+				else if (! reg_dst.has(it_src_bin->first))
+				{
+					// src[<region>][<asset>] without matching dst[<region>][<asset>]
+					reg_dst[it_src_bin->first] = it_src_bin->second;
+				}
+				else
+				{
+					// src[<region>][<asset>] with matching dst[<region>][<asset>]
+					// Matching stats bin in both source and destination regions.
+					// Iterate over those bin keys we know how to merge, leave the remainder untouched.
+					LLSD & bin_dst(reg_dst[it_src_bin->first]);
+					const LLSD & bin_src(reg_src[it_src_bin->first]);
+
+					for (int key_index(0); key_index < LL_ARRAY_SIZE(key_list); ++key_index)
+					{
+						const LLSD::String & key_name(key_list[key_index].mName);
+						
+						if (! bin_src.has(key_name))
+						{
+							// Missing src[<region>][<asset>][<field>]
+							continue;
+						}
+
+						const LLSD & src_value(bin_src[key_name]);
+				
+						if (! bin_dst.has(key_name))
+						{
+							// src[<region>][<asset>][<field>] without matching dst[<region>][<asset>][<field>]
+							bin_dst[key_name] = src_value;
+						}
+						else
+						{
+							// src[<region>][<asset>][<field>] with matching dst[<region>][<asset>][<field>]
+							LLSD & dst_value(bin_dst[key_name]);
+					
+							switch (key_list[key_index].mMergeOp)
+							{
+							case MOP_ADD_INT:
+								// Simple counts, just add
+								dst_value = dst_value.asInteger() + src_value.asInteger();
+						
+								break;
+						
+							case MOP_MIN_REAL:
+								// Minimum
+								dst_value = llmin(dst_value.asReal(), src_value.asReal());
+								break;
+
+							case MOP_MAX_REAL:
+								// Maximum
+								dst_value = llmax(dst_value.asReal(), src_value.asReal());
+								break;
+
+							case MOP_MEAN_REAL:
+							    {
+									// Mean
+									const LLSD::String & weight_key(key_list[key_index].mMergeOpArg);
+									F64 src_weight(bin_src[weight_key].asReal());
+									F64 dst_weight(bin_dst[weight_key].asReal());
+									F64 tot_weight(src_weight + dst_weight);
+									if (tot_weight >= F64(0.5))
+									{
+										dst_value = (((dst_value.asReal() * dst_weight)
+													  + (src_value.asReal() * src_weight))
+													 / tot_weight);
+									}
+								}
+								break;
+						
+							default:
+								break;
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+
 // ------------------------------------------------------
 // Global free-function definitions (LLViewerAssetStatsFF namespace)
 // ------------------------------------------------------
@@ -377,7 +571,43 @@ cleanup()
 	delete gViewerAssetStatsThread1;
 	gViewerAssetStatsThread1 = 0;
 }
+
+
+void
+merge_stats(const LLSD & src, LLSD & dst)
+{
+	static const LLSD::String regions_key("regions");
+	static const LLSD::String dur_key("duration");
+
+	// Trivial cases first
+	if (! src.isMap())
+	{
+		return;
+	}
+
+	if (! dst.isMap())
+	{
+		dst = src;
+		return;
+	}
 	
+	// Okay, both src and dst are maps at this point.
+	// Collector class know how to merge it's part
+	LLViewerAssetStats::mergeLLSD(src, dst);
+
+	// Now merge non-collector bits manually.
+	const LLSD::map_const_iterator it_end(src.endMap());
+	for (LLSD::map_const_iterator it(src.beginMap()); it_end != it; ++it)
+	{
+		if (regions_key == it->first || dur_key == it->first)
+			continue;
+
+		if (dst.has(it->first))
+			continue;
+
+		dst[it->first] = it->second;
+	}
+}
 
 } // namespace LLViewerAssetStatsFF
 
diff --git a/indra/newview/llviewerassetstats.h b/indra/newview/llviewerassetstats.h
index efd0897bb8..65ecdca4a0 100644
--- a/indra/newview/llviewerassetstats.h
+++ b/indra/newview/llviewerassetstats.h
@@ -83,10 +83,10 @@ class LLViewerAssetStats
 public:
 	enum EViewerAssetCategories
 	{
-		EVACTextureTempHTTPGet,			//< Texture GETs
-		EVACTextureTempUDPGet,			//< Texture GETs
-		EVACTextureNonTempHTTPGet,		//< Texture GETs
-		EVACTextureNonTempUDPGet,		//< Texture GETs
+		EVACTextureTempHTTPGet,			//< Texture GETs - temp/baked, HTTP
+		EVACTextureTempUDPGet,			//< Texture GETs - temp/baked, UDP
+		EVACTextureNonTempHTTPGet,		//< Texture GETs - perm, HTTP
+		EVACTextureNonTempUDPGet,		//< Texture GETs - perm, UDP
 		EVACWearableUDPGet,				//< Wearable GETs
 		EVACSoundUDPGet,				//< Sound GETs
 		EVACGestureUDPGet,				//< Gesture GETs
@@ -103,7 +103,11 @@ public:
 	typedef U64 duration_t;
 	
 	/**
-	 * Collected data for a single region visited by the avatar.
+	 * @brief Collected data for a single region visited by the avatar.
+	 *
+	 * Fairly simple, for each asset bin enumerated above a count
+	 * of enqueue and dequeue operations and simple stats on response
+	 * times for completed requests.
 	 */
 	class PerRegionStats : public LLRefCount
 	{
@@ -118,8 +122,15 @@ public:
 		
 		void reset();
 
+		// Apply current running time to total and reset start point.
+		// Return current timestamp as a convenience.
+		void accumulateTime(duration_t now);
+		
 	public:
 		LLUUID mRegionID;
+		duration_t mTotalTime;
+		duration_t mStartTimestamp;
+		
 		struct
 		{
 			LLSimpleStatCounter			mEnqueued;
@@ -142,13 +153,17 @@ public:
 	// collection calls.
 	void setRegionID(const LLUUID & region_id);
 
-	// Non-Cached GET Requests
+	// Asset GET Requests
 	void recordGetEnqueued(LLViewerAssetType::EType at, bool with_http, bool is_temp);
 	void recordGetDequeued(LLViewerAssetType::EType at, bool with_http, bool is_temp);
 	void recordGetServiced(LLViewerAssetType::EType at, bool with_http, bool is_temp, duration_t duration);
 
-	// Retrieve current metrics for all visited regions.
-	const LLSD asLLSD() const;
+	// Retrieve current metrics for all visited regions (NULL region UUID excluded)
+	LLSD asLLSD();
+
+	// Merge two LLSD's structured as per asLLSD().  If inputs are not
+	// correctly formed, result is undefined (little defensive action).
+	static void mergeLLSD(const LLSD & src, LLSD & dst);
 	
 protected:
 	typedef std::map<LLUUID, LLPointer<PerRegionStats> > PerRegionContainer;
@@ -165,6 +180,9 @@ protected:
 
 	// Metrics data for all regions during one collection cycle
 	PerRegionContainer mRegionStats;
+
+	// Time of last reset
+	duration_t mResetTimestamp;
 };
 
 
@@ -188,6 +206,17 @@ extern LLViewerAssetStats * gViewerAssetStatsThread1;
 
 namespace LLViewerAssetStatsFF
 {
+/**
+ * @brief Allocation and deallocation of globals.
+ *
+ * init() should be called before threads are started that will access it though
+ * you'll likely get away with calling it afterwards.  cleanup() should only be
+ * called after threads are shutdown to prevent races on the global pointers.
+ */
+void init();
+
+void cleanup();
+
 /**
  * We have many timers, clocks etc. in the runtime.  This is the
  * canonical timestamp for these metrics which is compatible with
@@ -224,15 +253,16 @@ void record_response_thread1(LLViewerAssetType::EType at, bool with_http, bool i
 						  LLViewerAssetStats::duration_t duration);
 
 /**
- * @brief Allocation and deallocation of globals.
+ * @brief Merge two LLSD reports from different collector instances
  *
- * init() should be called before threads are started that will access it though
- * you'll likely get away with calling it afterwards.  cleanup() should only be
- * called after threads are shutdown to prevent races on the global pointers.
+ * Use this to merge the LLSD's from two threads.  For top-level,
+ * non-region data the destination (dst) is considered authoritative
+ * if the key is present in both source and destination.  For
+ * regions, a numerical merge is performed when data are present in
+ * both source and destination and the 'right thing' is done for
+ * counts, minimums, maximums and averages.
  */
-void init();
-
-void cleanup();
+void merge_stats(const LLSD & src, LLSD & dst);
 
 } // namespace LLViewerAssetStatsFF
 
diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp
index c3c38ef925..e8cde5fc5d 100644
--- a/indra/newview/tests/llviewerassetstats_test.cpp
+++ b/indra/newview/tests/llviewerassetstats_test.cpp
@@ -39,9 +39,11 @@
 #include "lltut.h"
 #include "../llviewerassetstats.h"
 #include "lluuid.h"
+#include "llsdutil.h"
 
 static const char * all_keys[] = 
 {
+	"duration",
 	"get_other",
 	"get_texture_temp_http",
 	"get_texture_temp_udp",
@@ -77,11 +79,13 @@ static const char * sub_keys[] =
 static const LLUUID region1("4e2d81a3-6263-6ffe-ad5c-8ce04bee07e8");
 static const LLUUID region2("68762cc8-b68b-4e45-854b-e830734f2d4a");
 
+#if 0
 static bool
 is_empty_map(const LLSD & sd)
 {
 	return sd.isMap() && 0 == sd.size();
 }
+#endif
 
 static bool
 is_single_key_map(const LLSD & sd, const std::string & key)
@@ -95,6 +99,12 @@ is_double_key_map(const LLSD & sd, const std::string & key1, const std::string &
 	return sd.isMap() && 2 == sd.size() && sd.has(key1) && sd.has(key2);
 }
 
+static bool
+is_no_stats_map(const LLSD & sd)
+{
+	return is_double_key_map(sd, "duration", "regions");
+}
+
 namespace tut
 {
 	struct tst_viewerassetstats_index
@@ -131,14 +141,15 @@ namespace tut
 
 		// Default (NULL) region ID doesn't produce LLSD results so should
 		// get an empty map back from output
-		ensure("Null LLSD initially", is_empty_map(sd_full));
+		ensure("Stat-less LLSD initially", is_no_stats_map(sd_full));
 
 		// Once the region is set, we will get a response even with no data collection
 		it->setRegionID(region1);
 		sd_full = it->asLLSD();
-		ensure("Correct single-key LLSD map", is_single_key_map(sd_full, region1.asString()));
-
-		LLSD sd = sd_full[region1.asString()];
+		ensure("Correct single-key LLSD map root", is_double_key_map(sd_full, "duration", "regions"));
+		ensure("Correct single-key LLSD map regions", is_single_key_map(sd_full["regions"], region1.asString()));
+		
+		LLSD sd = sd_full["regions"][region1.asString()];
 
 		delete it;
 			
@@ -167,7 +178,8 @@ namespace tut
 		it->setRegionID(region1);
 		
 		LLSD sd = it->asLLSD();
-		ensure("Correct single-key LLSD map", is_single_key_map(sd, region1.asString()));
+		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
+		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1.asString()));
 		sd = sd[region1.asString()];
 		
 		delete it;
@@ -191,8 +203,9 @@ namespace tut
 		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false);
 
 		LLSD sd = gViewerAssetStatsMain->asLLSD();
-		ensure("Correct single-key LLSD map", is_single_key_map(sd, region1.asString()));
-		sd = sd[region1.asString()];
+		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
+		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1.asString()));
+		sd = sd["regions"][region1.asString()];
 		
 		// Check a few points on the tree for content
 		ensure("sd[get_texture_non_temp_udp][enqueued] is 1", (1 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger()));
@@ -204,7 +217,7 @@ namespace tut
 		// Reset and check zeros...
 		// Reset leaves current region in place
 		gViewerAssetStatsMain->reset();
-		sd = gViewerAssetStatsMain->asLLSD()[region1.asString()];
+		sd = gViewerAssetStatsMain->asLLSD()["regions"][region1.asString()];
 		
 		delete gViewerAssetStatsMain;
 		gViewerAssetStatsMain = NULL;
@@ -228,10 +241,11 @@ namespace tut
 		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false);
 
 		LLSD sd = gViewerAssetStatsThread1->asLLSD();
-		ensure("Other collector is empty", is_empty_map(sd));
+		ensure("Other collector is empty", is_no_stats_map(sd));
 		sd = gViewerAssetStatsMain->asLLSD();
-		ensure("Correct single-key LLSD map", is_single_key_map(sd, region1.asString()));
-		sd = sd[region1.asString()];
+		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
+		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1.asString()));
+		sd = sd["regions"][region1.asString()];
 		
 		// Check a few points on the tree for content
 		ensure("sd[get_texture_non_temp_udp][enqueued] is 1", (1 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger()));
@@ -243,7 +257,7 @@ namespace tut
 		// Reset and check zeros...
 		// Reset leaves current region in place
 		gViewerAssetStatsMain->reset();
-		sd = gViewerAssetStatsMain->asLLSD()[region1.asString()];
+		sd = gViewerAssetStatsMain->asLLSD()["regions"][region1.asString()];
 		
 		delete gViewerAssetStatsMain;
 		gViewerAssetStatsMain = NULL;
@@ -277,9 +291,12 @@ namespace tut
 
 		LLSD sd = gViewerAssetStatsMain->asLLSD();
 
-		ensure("Correct double-key LLSD map", is_double_key_map(sd, region1.asString(), region2.asString()));
-		LLSD sd1 = sd[region1.asString()];
-		LLSD sd2 = sd[region2.asString()];
+		// std::cout << sd << std::endl;
+		
+		ensure("Correct double-key LLSD map root", is_double_key_map(sd, "duration", "regions"));
+		ensure("Correct double-key LLSD map regions", is_double_key_map(sd["regions"], region1.asString(), region2.asString()));
+		LLSD sd1 = sd["regions"][region1.asString()];
+		LLSD sd2 = sd["regions"][region2.asString()];
 		
 		// Check a few points on the tree for content
 		ensure("sd1[get_texture_non_temp_udp][enqueued] is 1", (1 == sd1["get_texture_non_temp_udp"]["enqueued"].asInteger()));
@@ -297,8 +314,9 @@ namespace tut
 		// Reset leaves current region in place
 		gViewerAssetStatsMain->reset();
 		sd = gViewerAssetStatsMain->asLLSD();
-		ensure("Correct single-key LLSD map", is_single_key_map(sd, region2.asString()));
-		sd2 = sd[region2.asString()];
+		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
+		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region2.asString()));
+		sd2 = sd["regions"][region2.asString()];
 		
 		delete gViewerAssetStatsMain;
 		gViewerAssetStatsMain = NULL;
@@ -345,9 +363,10 @@ namespace tut
 
 		LLSD sd = gViewerAssetStatsMain->asLLSD();
 
-		ensure("Correct double-key LLSD map", is_double_key_map(sd, region1.asString(), region2.asString()));
-		LLSD sd1 = sd[region1.asString()];
-		LLSD sd2 = sd[region2.asString()];
+		ensure("Correct double-key LLSD map root", is_double_key_map(sd, "duration", "regions"));
+		ensure("Correct double-key LLSD map regions", is_double_key_map(sd["regions"], region1.asString(), region2.asString()));
+		LLSD sd1 = sd["regions"][region1.asString()];
+		LLSD sd2 = sd["regions"][region2.asString()];
 		
 		// Check a few points on the tree for content
 		ensure("sd1[get_texture_non_temp_udp][enqueued] is 1", (1 == sd1["get_texture_non_temp_udp"]["enqueued"].asInteger()));
@@ -365,8 +384,9 @@ namespace tut
 		// Reset leaves current region in place
 		gViewerAssetStatsMain->reset();
 		sd = gViewerAssetStatsMain->asLLSD();
-		ensure("Correct single-key LLSD map", is_single_key_map(sd, region2.asString()));
-		sd2 = sd[region2.asString()];
+		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "duration", "regions"));
+		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region2.asString()));
+		sd2 = sd["regions"][region2.asString()];
 		
 		delete gViewerAssetStatsMain;
 		gViewerAssetStatsMain = NULL;
@@ -407,10 +427,11 @@ namespace tut
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
 
 		LLSD sd = gViewerAssetStatsThread1->asLLSD();
-		ensure("Other collector is empty", is_empty_map(sd));
+		ensure("Other collector is empty", is_no_stats_map(sd));
 		sd = gViewerAssetStatsMain->asLLSD();
-		ensure("Correct single-key LLSD map", is_single_key_map(sd, region1.asString()));
-		sd = sd[region1.asString()];
+		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
+		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1.asString()));
+		sd = sd["regions"][region1.asString()];
 		
 		// Check a few points on the tree for content
 		ensure("sd[get_gesture_udp][enqueued] is 0", (0 == sd["get_gesture_udp"]["enqueued"].asInteger()));
@@ -425,7 +446,7 @@ namespace tut
 		// Reset and check zeros...
 		// Reset leaves current region in place
 		gViewerAssetStatsMain->reset();
-		sd = gViewerAssetStatsMain->asLLSD()[region1.asString()];
+		sd = gViewerAssetStatsMain->asLLSD()["regions"][region1.asString()];
 		
 		delete gViewerAssetStatsMain;
 		gViewerAssetStatsMain = NULL;
@@ -436,4 +457,65 @@ namespace tut
 		ensure("sd[get_gesture_udp][dequeued] is reset", (0 == sd["get_gesture_udp"]["dequeued"].asInteger()));
 	}
 
+	// Check that the LLSD merger knows what it's doing (basic test)
+	template<> template<>
+	void tst_viewerassetstats_index_object_t::test<9>()
+	{
+		LLSD::String reg1_name = region1.asString();
+		LLSD::String reg2_name = region2.asString();
+
+		LLSD reg1_stats = LLSD::emptyMap();
+		LLSD reg2_stats = LLSD::emptyMap();
+
+		LLSD & tmp_other1 = reg1_stats["get_other"];
+		tmp_other1["enqueued"] = 4;
+		tmp_other1["dequeued"] = 4;
+		tmp_other1["resp_count"] = 8;
+		tmp_other1["resp_max"] = F64(23.2892);
+		tmp_other1["resp_min"] = F64(0.2829);
+		tmp_other1["resp_mean"] = F64(2.298928);
+
+		LLSD & tmp_other2 = reg2_stats["get_other"];
+		tmp_other2["enqueued"] = 8;
+		tmp_other2["dequeued"] = 7;
+		tmp_other2["resp_count"] = 3;
+		tmp_other2["resp_max"] = F64(6.5);
+		tmp_other2["resp_min"] = F64(0.01);
+		tmp_other2["resp_mean"] = F64(4.1);
+		
+		{
+			LLSD src = LLSD::emptyMap();
+			LLSD dst = LLSD::emptyMap();
+
+			src["regions"][reg1_name] = reg1_stats;
+			src["duration"] = 24;
+			dst["regions"][reg2_name] = reg2_stats;
+			dst["duration"] = 36;
+
+			LLViewerAssetStats::mergeLLSD(src, dst);
+		
+			ensure("region 1 in merged stats", llsd_equals(reg1_stats, dst["regions"][reg1_name]));
+			ensure("region 2 still in merged stats", llsd_equals(reg2_stats, dst["regions"][reg2_name]));
+		}
+
+		{
+			LLSD src = LLSD::emptyMap();
+			LLSD dst = LLSD::emptyMap();
+
+			src["regions"][reg1_name] = reg1_stats;
+			src["duration"] = 24;
+			dst["regions"][reg1_name] = reg2_stats;
+			dst["duration"] = 36;
+
+			LLViewerAssetStats::mergeLLSD(src, dst);
+
+			ensure("src not ruined", llsd_equals(reg1_stats, src["regions"][reg1_name]));
+			ensure_equals("added enqueued counts", dst["regions"][reg1_name]["get_other"]["enqueued"].asInteger(), 12);
+			ensure_equals("added dequeued counts", dst["regions"][reg1_name]["get_other"]["dequeued"].asInteger(), 11);
+			ensure_equals("added response counts", dst["regions"][reg1_name]["get_other"]["resp_count"].asInteger(), 11);
+			ensure_approximately_equals("min'd minimum response times", dst["regions"][reg1_name]["get_other"]["resp_min"].asReal(), 0.01, 20);
+			ensure_approximately_equals("max'd maximum response times", dst["regions"][reg1_name]["get_other"]["resp_max"].asReal(), 23.2892, 20);
+			ensure_approximately_equals("weighted mean of means", dst["regions"][reg1_name]["get_other"]["resp_mean"].asReal(), 2.7901295, 20);
+		}
+	}
 }
-- 
cgit v1.2.3


From f98a622325d8982d32ae98e189f5d3ec6ada183f Mon Sep 17 00:00:00 2001
From: Monty Brandenberg <monty@lindenlab.com>
Date: Mon, 22 Nov 2010 10:26:25 -0800
Subject: ESC-154 ESC-156  Metrics integration into viewer's threads Removed
 declared but undefined interfaces from LLTextureFetch family. Had inserted
 the cross-thread command processor into some of LLTextureFetchWorker's
 processing which was unnatural and probably wrong.  Moved it to
 LLTextureFetch which turned out to be far, far more natural.  Better
 documentation on the asLLSD() format.  Refined LLSD stats merger logic and
 enhanced unit tests to verify same.

---
 indra/newview/lltexturefetch.cpp                | 40 ++++++++-------
 indra/newview/lltexturefetch.h                  | 10 ++--
 indra/newview/llviewerassetstats.cpp            | 68 ++++++++++---------------
 indra/newview/llviewerassetstats.h              | 38 ++++++++++++--
 indra/newview/tests/llviewerassetstats_test.cpp |  4 +-
 5 files changed, 91 insertions(+), 69 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index d303d425c8..e574a35479 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -405,7 +405,7 @@ namespace
  * into the respective collector unconcerned with locking and
  * the state of any other thread.  But when the agent moves into
  * a different region or the metrics timer expires and a report
- * needs to be sent back to the grid, messaging across grids
+ * needs to be sent back to the grid, messaging across threads
  * is required to distribute data and perform global actions.
  * In pseudo-UML, it looks like:
  *
@@ -484,7 +484,11 @@ public:
 	virtual ~TFRequest()
 		{}
 
-	virtual bool doWork(LLTextureFetchWorker * worker) = 0;
+	// Patterned after QueuedRequest's method but expected behavior
+	// is different.  Always expected to complete on the first call
+	// and work dispatcher will assume the same and delete the
+	// request after invocation.
+	virtual bool doWork(LLTextureFetch * fetcher) = 0;
 };
 
 
@@ -511,7 +515,7 @@ public:
 	virtual ~TFReqSetRegion()
 		{}
 
-	virtual bool doWork(LLTextureFetchWorker * worker);
+	virtual bool doWork(LLTextureFetch * fetcher);
 		
 public:
 	const LLUUID mRegionID;
@@ -557,7 +561,7 @@ public:
 
 	virtual ~TFReqSendMetrics();
 
-	virtual bool doWork(LLTextureFetchWorker * worker);
+	virtual bool doWork(LLTextureFetch * fetcher);
 		
 public:
 	const std::string mCapsURL;
@@ -808,9 +812,6 @@ bool LLTextureFetchWorker::doWork(S32 param)
 		}
 	}
 
-	// Run a cross-thread command, if any.
-	mFetcher->cmdDoWork(this);
-	
 	if(mImagePriority < F_ALMOST_ZERO)
 	{
 		if (mState == INIT || mState == LOAD_FROM_NETWORK || mState == LOAD_FROM_SIMULATOR)
@@ -2188,6 +2189,9 @@ void LLTextureFetch::threadedUpdate()
 	}
 	process_timer.reset();
 	
+	// Run a cross-thread command, if any.
+	cmdDoWork();
+	
 	// Update Curl on same thread as mCurlGetRequest was constructed
 	S32 processed = mCurlGetRequest->process();
 	if (processed > 0)
@@ -2695,22 +2699,22 @@ TFRequest * LLTextureFetch::cmdDequeue()
 	return ret;
 }
 
-void LLTextureFetch::cmdDoWork(LLTextureFetchWorker * worker)
+void LLTextureFetch::cmdDoWork()
 {
-	// Queue is expected to be locked here.
-
 	if (mDebugPause)
 	{
 		return;  // debug: don't do any work
 	}
 
+	lockQueue();
 	TFRequest * req = cmdDequeue();
 	if (req)
 	{
 		// One request per pass should really be enough for this.
-		req->doWork(worker);
+		req->doWork(this);
 		delete req;
 	}
+	unlockQueue();
 }
 
 
@@ -2727,7 +2731,7 @@ namespace
  * Thread:  Thread1 (TextureFetch)
  */
 bool
-TFReqSetRegion::doWork(LLTextureFetchWorker *)
+TFReqSetRegion::doWork(LLTextureFetch *)
 {
 	LLViewerAssetStatsFF::set_region_thread1(mRegionID);
 
@@ -2749,7 +2753,7 @@ TFReqSendMetrics::~TFReqSendMetrics()
  * Thread:  Thread1 (TextureFetch)
  */
 bool
-TFReqSendMetrics::doWork(LLTextureFetchWorker * fetch_worker)
+TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
 {
 	/*
 	 * HTTP POST responder.  Doesn't do much but tries to
@@ -2818,11 +2822,11 @@ TFReqSendMetrics::doWork(LLTextureFetchWorker * fetch_worker)
 	if (! mCapsURL.empty())
 	{
 		LLCurlRequest::headers_t headers;
-		fetch_worker->getFetcher().getCurlRequest().post(mCapsURL,
-														 headers,
-														 thread1_stats,
-														 new lcl_responder(LLTextureFetch::svMetricsDataBreak,
-																		   reporting_started));
+		fetcher->getCurlRequest().post(mCapsURL,
+									   headers,
+									   thread1_stats,
+									   new lcl_responder(LLTextureFetch::svMetricsDataBreak,
+														 reporting_started));
 	}
 	else
 	{
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index 220305d881..88b7e4a16b 100644
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -85,7 +85,7 @@ public:
 
 	LLTextureInfo* getTextureInfo() { return &mTextureInfo; }
 
-	// Commands available to other threads.
+	// Commands available to other threads to control metrics gathering operations.
 	void commandSetRegion(const LLUUID & region_id);
 	void commandSendMetrics(const std::string & caps_url, LLSD * report_main);
 	void commandDataBreak();
@@ -98,8 +98,6 @@ protected:
 	void addToHTTPQueue(const LLUUID& id);
 	void removeFromHTTPQueue(const LLUUID& id, S32 received_size = 0);
 	void removeRequest(LLTextureFetchWorker* worker, bool cancel);
-	// Called from worker thread (during doWork)
-	void processCurlRequests();
 
 	// Overrides from the LLThread tree
 	bool runCondition();
@@ -110,10 +108,10 @@ private:
 	/*virtual*/ void endThread(void);
 	/*virtual*/ void threadedUpdate(void);
 
-	// command helpers
+	// Metrics command helpers
 	void cmdEnqueue(TFRequest *);
 	TFRequest * cmdDequeue();
-	void cmdDoWork(LLTextureFetchWorker* worker);
+	void cmdDoWork();
 	
 public:
 	LLUUID mDebugID;
@@ -146,7 +144,7 @@ private:
 
 	U32 mHTTPTextureBits;
 
-	// Special cross-thread command queue.  This command queue
+	// Out-of-band cross-thread command queue.  This command queue
 	// is logically tied to LLQueuedThread's list of
 	// QueuedRequest instances and so must be covered by the
 	// same locks.
diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp
index c0287863f6..c3e58cdd56 100644
--- a/indra/newview/llviewerassetstats.cpp
+++ b/indra/newview/llviewerassetstats.cpp
@@ -230,7 +230,7 @@ LLViewerAssetStats::asLLSD()
 			LLSD::String("get_other")
 		};
 
-	// Sub-tags.  If you add or delete from this list, mergeLLSD() must be updated.
+	// Sub-tags.  If you add or delete from this list, mergeRegionsLLSD() must be updated.
 	static const LLSD::String enq_tag("enqueued");
 	static const LLSD::String deq_tag("dequeued");
 	static const LLSD::String rcnt_tag("resp_count");
@@ -281,7 +281,7 @@ LLViewerAssetStats::asLLSD()
 }
 
 /* static */ void
-LLViewerAssetStats::mergeLLSD(const LLSD & src, LLSD & dst)
+LLViewerAssetStats::mergeRegionsLLSD(const LLSD & src, LLSD & dst)
 {
 	// Merge operator definitions
 	static const int MOP_ADD_INT(0);
@@ -290,11 +290,6 @@ LLViewerAssetStats::mergeLLSD(const LLSD & src, LLSD & dst)
 	static const int MOP_MEAN_REAL(3);	// Requires a 'mMergeOpArg' to weight the input terms
 
 	static const LLSD::String regions_key("regions");
-	static const LLSD::String root_key_list[] =
-		{
-			"duration",
-			regions_key
-		};
 	
 	static const struct
 		{
@@ -318,35 +313,29 @@ LLViewerAssetStats::mergeLLSD(const LLSD & src, LLSD & dst)
 			{ "resp_max", MOP_MAX_REAL, "" }
 		};
 
-	// First normalized the root keys but remember if we need to do full merge
-	const bool needs_deep_merge(src.has(regions_key) && dst.has(regions_key));
-	
-	for (int root_index(0); root_index < LL_ARRAY_SIZE(root_key_list); ++root_index)
+	// Trivial checks
+	if (! src.has(regions_key))
 	{
-		const LLSD::String & key_name(root_key_list[root_index]);
-						
-		if ((! src.has(key_name)) || dst.has(key_name))
-			continue;
-
-		// key present in source, not in dst here
-		dst[key_name] = src[key_name];
+		return;
 	}
 
-	if (! needs_deep_merge)
+	if (! dst.has(regions_key))
+	{
+		dst[regions_key] = src[regions_key];
 		return;
-
-	// Okay, had both src and dst 'regions' section, do the deep merge
-
+	}
+	
+	// Non-trivial cases requiring a deep merge.
 	const LLSD & root_src(src[regions_key]);
 	LLSD & root_dst(dst[regions_key]);
 	
-	const LLSD::map_const_iterator it_end(root_src.endMap());
-	for (LLSD::map_const_iterator it(root_src.beginMap()); it_end != it; ++it)
+	const LLSD::map_const_iterator it_uuid_end(root_src.endMap());
+	for (LLSD::map_const_iterator it_uuid(root_src.beginMap()); it_uuid_end != it_uuid; ++it_uuid)
 	{
-		if (! root_dst.has(it->first))
+		if (! root_dst.has(it_uuid->first))
 		{
 			// src[<region>] without matching dst[<region>]
-			root_dst[it->first] = it->second;
+			root_dst[it_uuid->first] = it_uuid->second;
 		}
 		else
 		{
@@ -354,30 +343,30 @@ LLViewerAssetStats::mergeLLSD(const LLSD & src, LLSD & dst)
 			// We have matching source and destination regions.
 			// Now iterate over each asset bin in the region status.  Could iterate over
 			// an explicit list but this will do as well.
-			LLSD & reg_dst(root_dst[it->first]);
-			const LLSD & reg_src(root_src[it->first]);
+			LLSD & reg_dst(root_dst[it_uuid->first]);
+			const LLSD & reg_src(root_src[it_uuid->first]);
 
-			const LLSD::map_const_iterator it_src_bin_end(reg_src.endMap());
-			for (LLSD::map_const_iterator it_src_bin(reg_src.beginMap()); it_src_bin_end != it_src_bin; ++it_src_bin)
+			const LLSD::map_const_iterator it_sets_end(reg_src.endMap());
+			for (LLSD::map_const_iterator it_sets(reg_src.beginMap()); it_sets_end != it_sets; ++it_sets)
 			{
 				static const LLSD::String no_touch_1("duration");
 
-				if (no_touch_1 == it_src_bin->first)
+				if (no_touch_1 == it_sets->first)
 				{
 					continue;
 				}
-				else if (! reg_dst.has(it_src_bin->first))
+				else if (! reg_dst.has(it_sets->first))
 				{
 					// src[<region>][<asset>] without matching dst[<region>][<asset>]
-					reg_dst[it_src_bin->first] = it_src_bin->second;
+					reg_dst[it_sets->first] = it_sets->second;
 				}
 				else
 				{
 					// src[<region>][<asset>] with matching dst[<region>][<asset>]
 					// Matching stats bin in both source and destination regions.
 					// Iterate over those bin keys we know how to merge, leave the remainder untouched.
-					LLSD & bin_dst(reg_dst[it_src_bin->first]);
-					const LLSD & bin_src(reg_src[it_src_bin->first]);
+					LLSD & bin_dst(reg_dst[it_sets->first]);
+					const LLSD & bin_src(reg_src[it_sets->first]);
 
 					for (int key_index(0); key_index < LL_ARRAY_SIZE(key_list); ++key_index)
 					{
@@ -577,7 +566,6 @@ void
 merge_stats(const LLSD & src, LLSD & dst)
 {
 	static const LLSD::String regions_key("regions");
-	static const LLSD::String dur_key("duration");
 
 	// Trivial cases first
 	if (! src.isMap())
@@ -592,14 +580,14 @@ merge_stats(const LLSD & src, LLSD & dst)
 	}
 	
 	// Okay, both src and dst are maps at this point.
-	// Collector class know how to merge it's part
-	LLViewerAssetStats::mergeLLSD(src, dst);
+	// Collector class know how to merge the regions part.
+	LLViewerAssetStats::mergeRegionsLLSD(src, dst);
 
-	// Now merge non-collector bits manually.
+	// Now merge non-regions bits manually.
 	const LLSD::map_const_iterator it_end(src.endMap());
 	for (LLSD::map_const_iterator it(src.beginMap()); it_end != it; ++it)
 	{
-		if (regions_key == it->first || dur_key == it->first)
+		if (regions_key == it->first)
 			continue;
 
 		if (dst.has(it->first))
diff --git a/indra/newview/llviewerassetstats.h b/indra/newview/llviewerassetstats.h
index 65ecdca4a0..cb63b9c511 100644
--- a/indra/newview/llviewerassetstats.h
+++ b/indra/newview/llviewerassetstats.h
@@ -159,11 +159,43 @@ public:
 	void recordGetServiced(LLViewerAssetType::EType at, bool with_http, bool is_temp, duration_t duration);
 
 	// Retrieve current metrics for all visited regions (NULL region UUID excluded)
+    // Returned LLSD is structured as follows:
+	//
+	// &stats_group = {
+	//   enqueued   : int,
+	//   dequeued   : int,
+	//   resp_count : int,
+	//   resp_min   : float,
+	//   resp_max   : float,
+	//   resp_mean  : float
+	// }
+	//
+	// {
+	//   duration: int
+	//   regions: {
+	//     $: {
+	//       duration:                 : int,
+	//       get_texture_temp_http     : &stats_group,
+	//       get_texture_temp_udp      : &stats_group,
+	//       get_texture_non_temp_http : &stats_group,
+	//       get_texture_non_temp_udp  : &stats_group,
+	//       get_wearable_udp          : &stats_group,
+	//       get_sound_udp             : &stats_group,
+	//       get_gesture_udp           : &stats_group,
+	//       get_other                 : &stats_group
+	//     }
+	//   }
+	// }
 	LLSD asLLSD();
 
-	// Merge two LLSD's structured as per asLLSD().  If inputs are not
-	// correctly formed, result is undefined (little defensive action).
-	static void mergeLLSD(const LLSD & src, LLSD & dst);
+	// Merges the "regions" maps in two LLSDs structured as per asLLSD().
+	// This takes two LLSDs as returned by asLLSD() and intelligently
+	// merges the metrics contained in the maps indexed by "regions".
+	// The remainder of the top-level map of the LLSDs is left unchanged
+	// in expectation that callers will add other information at this
+	// level.  The "regions" information must be correctly formed or the
+	// final result is undefined (little defensive action).
+	static void mergeRegionsLLSD(const LLSD & src, LLSD & dst);
 	
 protected:
 	typedef std::map<LLUUID, LLPointer<PerRegionStats> > PerRegionContainer;
diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp
index e8cde5fc5d..a44712e8ad 100644
--- a/indra/newview/tests/llviewerassetstats_test.cpp
+++ b/indra/newview/tests/llviewerassetstats_test.cpp
@@ -492,7 +492,7 @@ namespace tut
 			dst["regions"][reg2_name] = reg2_stats;
 			dst["duration"] = 36;
 
-			LLViewerAssetStats::mergeLLSD(src, dst);
+			LLViewerAssetStats::mergeRegionsLLSD(src, dst);
 		
 			ensure("region 1 in merged stats", llsd_equals(reg1_stats, dst["regions"][reg1_name]));
 			ensure("region 2 still in merged stats", llsd_equals(reg2_stats, dst["regions"][reg2_name]));
@@ -507,7 +507,7 @@ namespace tut
 			dst["regions"][reg1_name] = reg2_stats;
 			dst["duration"] = 36;
 
-			LLViewerAssetStats::mergeLLSD(src, dst);
+			LLViewerAssetStats::mergeRegionsLLSD(src, dst);
 
 			ensure("src not ruined", llsd_equals(reg1_stats, src["regions"][reg1_name]));
 			ensure_equals("added enqueued counts", dst["regions"][reg1_name]["get_other"]["enqueued"].asInteger(), 12);
-- 
cgit v1.2.3


From 9ec3334184c71879c2f8bd0f27095b71c4302559 Mon Sep 17 00:00:00 2001
From: Monty Brandenberg <monty@lindenlab.com>
Date: Tue, 23 Nov 2010 13:31:22 -0500
Subject: ESC-154 ESC-156 Data collection and control for viewer metrics Detect
 QAMode (and new QAModeMetricsSubmode) settings which enable logging of
 metrics report locally and a faster cycle time to reduce test waiting.  Do
 this only in the main thread and propagate the result via collector
 constructors (will likely move that out and put it in
 llappviewer/lltexturefetch which is more correct scope).  Managed to deadlock
 myself with a recursive mutex (sheesh).

---
 indra/newview/llappviewer.cpp                   | 11 +++++++++--
 indra/newview/lltexturefetch.cpp                |  7 +++----
 indra/newview/llviewerassetstats.cpp            |  9 +++++----
 indra/newview/llviewerassetstats.h              | 14 ++++++++++----
 indra/newview/tests/llviewerassetstats_test.cpp | 18 +++++++++---------
 5 files changed, 36 insertions(+), 23 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index e696e1af84..587d887146 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -666,11 +666,18 @@ bool LLAppViewer::init()
 	
 	{
 		// Viewer metrics initialization
-		if (gSavedSettings.getBOOL("QAMode") && gSavedSettings.getBOOL("QAModeMetricsSubmode"))
+		static LLCachedControl<BOOL> metrics_submode(gSavedSettings,
+													 "QAModeMetricsSubmode",
+													 FALSE,
+													 "Enables metrics submode when QAMode is also enabled");
+
+		bool qa_mode(false);
+		if (gSavedSettings.getBOOL("QAMode") && metrics_submode)
 		{
 			app_metrics_interval = METRICS_INTERVAL_QA;
+			qa_mode = true;
 		}
-		LLViewerAssetStatsFF::init();
+		LLViewerAssetStatsFF::init(qa_mode);
 	}
 
     initThreads();
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index e574a35479..8e43084adb 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -2680,8 +2680,9 @@ void LLTextureFetch::cmdEnqueue(TFRequest * req)
 {
 	lockQueue();
 	mCommands.push_back(req);
-	wake();
 	unlockQueue();
+
+	wake();
 }
 
 TFRequest * LLTextureFetch::cmdDequeue()
@@ -2706,7 +2707,6 @@ void LLTextureFetch::cmdDoWork()
 		return;  // debug: don't do any work
 	}
 
-	lockQueue();
 	TFRequest * req = cmdDequeue();
 	if (req)
 	{
@@ -2714,7 +2714,6 @@ void LLTextureFetch::cmdDoWork()
 		req->doWork(this);
 		delete req;
 	}
-	unlockQueue();
 }
 
 
@@ -2834,7 +2833,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
 	}
 
 	// In QA mode, Metrics submode, log the result for ease of testing
-	if (gSavedSettings.getBOOL("QAMode") && gSavedSettings.getBOOL("QAModeMetricsSubmode"))
+	if (gViewerAssetStatsThread1->isQAMode())
 	{
 		LL_INFOS("QAViewerMetrics") << thread1_stats << LL_ENDL;
 	}
diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp
index c3e58cdd56..a63c1bf66d 100644
--- a/indra/newview/llviewerassetstats.cpp
+++ b/indra/newview/llviewerassetstats.cpp
@@ -129,7 +129,8 @@ LLViewerAssetStats::PerRegionStats::accumulateTime(duration_t now)
 // ------------------------------------------------------
 // LLViewerAssetStats class definition
 // ------------------------------------------------------
-LLViewerAssetStats::LLViewerAssetStats()
+LLViewerAssetStats::LLViewerAssetStats(bool qa_mode)
+	: mQAMode(qa_mode)
 {
 	reset();
 }
@@ -539,15 +540,15 @@ record_response_thread1(LLViewerAssetType::EType at, bool with_http, bool is_tem
 
 
 void
-init()
+init(bool qa_mode)
 {
 	if (! gViewerAssetStatsMain)
 	{
-		gViewerAssetStatsMain = new LLViewerAssetStats;
+		gViewerAssetStatsMain = new LLViewerAssetStats(qa_mode);
 	}
 	if (! gViewerAssetStatsThread1)
 	{
-		gViewerAssetStatsThread1 = new LLViewerAssetStats;
+		gViewerAssetStatsThread1 = new LLViewerAssetStats(qa_mode);
 	}
 }
 
diff --git a/indra/newview/llviewerassetstats.h b/indra/newview/llviewerassetstats.h
index cb63b9c511..1668a1bc9d 100644
--- a/indra/newview/llviewerassetstats.h
+++ b/indra/newview/llviewerassetstats.h
@@ -140,7 +140,7 @@ public:
 	};
 
 public:
-	LLViewerAssetStats();
+	LLViewerAssetStats(bool qa_mode);
 	// Default destructor is correct.
 	LLViewerAssetStats & operator=(const LLViewerAssetStats &);			// Not defined
 
@@ -196,6 +196,10 @@ public:
 	// level.  The "regions" information must be correctly formed or the
 	// final result is undefined (little defensive action).
 	static void mergeRegionsLLSD(const LLSD & src, LLSD & dst);
+
+	// QA mode is established during initialization so we don't
+	// touch LLSD at runtime.
+	bool isQAMode() const { return mQAMode; }
 	
 protected:
 	typedef std::map<LLUUID, LLPointer<PerRegionStats> > PerRegionContainer;
@@ -215,6 +219,9 @@ protected:
 
 	// Time of last reset
 	duration_t mResetTimestamp;
+
+	// QA Mode
+	const bool mQAMode;
 };
 
 
@@ -245,7 +252,7 @@ namespace LLViewerAssetStatsFF
  * you'll likely get away with calling it afterwards.  cleanup() should only be
  * called after threads are shutdown to prevent races on the global pointers.
  */
-void init();
+void init(bool qa_mode);
 
 void cleanup();
 
@@ -298,5 +305,4 @@ void merge_stats(const LLSD & src, LLSD & dst);
 
 } // namespace LLViewerAssetStatsFF
 
-
-#endif	// LL_LLVIEWERASSETSTATUS_H
+#endif // LL_LLVIEWERASSETSTATUS_H
diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp
index a44712e8ad..5a178fc585 100644
--- a/indra/newview/tests/llviewerassetstats_test.cpp
+++ b/indra/newview/tests/llviewerassetstats_test.cpp
@@ -133,7 +133,7 @@ namespace tut
 	{
 		ensure("Global gViewerAssetStatsMain should be NULL", (NULL == gViewerAssetStatsMain));
 
-		LLViewerAssetStats * it = new LLViewerAssetStats();
+		LLViewerAssetStats * it = new LLViewerAssetStats(false);
 
 		ensure("Global gViewerAssetStatsMain should still be NULL", (NULL == gViewerAssetStatsMain));
 
@@ -174,7 +174,7 @@ namespace tut
 	template<> template<>
 	void tst_viewerassetstats_index_object_t::test<3>()
 	{
-		LLViewerAssetStats * it = new LLViewerAssetStats();
+		LLViewerAssetStats * it = new LLViewerAssetStats(false);
 		it->setRegionID(region1);
 		
 		LLSD sd = it->asLLSD();
@@ -193,7 +193,7 @@ namespace tut
 	template<> template<>
 	void tst_viewerassetstats_index_object_t::test<4>()
 	{
-		gViewerAssetStatsMain = new LLViewerAssetStats();
+		gViewerAssetStatsMain = new LLViewerAssetStats(false);
 		LLViewerAssetStatsFF::set_region_main(region1);
 
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false);
@@ -230,8 +230,8 @@ namespace tut
 	template<> template<>
 	void tst_viewerassetstats_index_object_t::test<5>()
 	{
-		gViewerAssetStatsThread1 = new LLViewerAssetStats();
-		gViewerAssetStatsMain = new LLViewerAssetStats();
+		gViewerAssetStatsThread1 = new LLViewerAssetStats(false);
+		gViewerAssetStatsMain = new LLViewerAssetStats(false);
 		LLViewerAssetStatsFF::set_region_main(region1);
 
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false);
@@ -272,7 +272,7 @@ namespace tut
 	template<> template<>
 	void tst_viewerassetstats_index_object_t::test<6>()
 	{
-		gViewerAssetStatsMain = new LLViewerAssetStats();
+		gViewerAssetStatsMain = new LLViewerAssetStats(false);
 
 		LLViewerAssetStatsFF::set_region_main(region1);
 
@@ -329,7 +329,7 @@ namespace tut
 	template<> template<>
 	void tst_viewerassetstats_index_object_t::test<7>()
 	{
-		gViewerAssetStatsMain = new LLViewerAssetStats();
+		gViewerAssetStatsMain = new LLViewerAssetStats(false);
 
 		LLViewerAssetStatsFF::set_region_main(region1);
 
@@ -399,8 +399,8 @@ namespace tut
 	template<> template<>
 	void tst_viewerassetstats_index_object_t::test<8>()
 	{
-		gViewerAssetStatsThread1 = new LLViewerAssetStats();
-		gViewerAssetStatsMain = new LLViewerAssetStats();
+		gViewerAssetStatsThread1 = new LLViewerAssetStats(false);
+		gViewerAssetStatsMain = new LLViewerAssetStats(false);
 		LLViewerAssetStatsFF::set_region_main(region1);
 
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false);
-- 
cgit v1.2.3


From 3962b155b4939f831dfd82701d46c4f15aa9f7ac Mon Sep 17 00:00:00 2001
From: Monty Brandenberg <monty@lindenlab.com>
Date: Tue, 23 Nov 2010 12:29:15 -0800
Subject: ESC-154 ESC-156 Integrating metrics collector into viewer. After
 discussions, renamed 'QAModeMetricsSubmetrics' to 'QAModeMetrics' and
 confirmed that LLCachedControl<> is the way to go.  Moved the resulting flag
 out of LLViewerAssetStats (where it didn't belong) and it lives in both
 LLAppViewer and LLTextureFetch where it does belong.

---
 indra/newview/llappviewer.cpp                   | 17 +++++++-----
 indra/newview/lltexturefetch.cpp                |  7 ++---
 indra/newview/lltexturefetch.h                  | 36 ++++++++++++++++++++++---
 indra/newview/llviewerassetstats.cpp            |  9 +++----
 indra/newview/llviewerassetstats.h              | 11 ++------
 indra/newview/tests/llviewerassetstats_test.cpp | 18 ++++++-------
 6 files changed, 62 insertions(+), 36 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 587d887146..07f4e71ebf 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -339,6 +339,7 @@ LLAppViewer::LLUpdaterInfo *LLAppViewer::sUpdaterInfo = NULL ;
 static const F32 METRICS_INTERVAL_DEFAULT = 600.0;
 static const F32 METRICS_INTERVAL_QA = 30.0;
 static F32 app_metrics_interval = METRICS_INTERVAL_DEFAULT;
+static bool app_metrics_qa_mode = false;
 
 void idle_afk_check()
 {
@@ -667,17 +668,16 @@ bool LLAppViewer::init()
 	{
 		// Viewer metrics initialization
 		static LLCachedControl<BOOL> metrics_submode(gSavedSettings,
-													 "QAModeMetricsSubmode",
+													 "QAModeMetrics",
 													 FALSE,
-													 "Enables metrics submode when QAMode is also enabled");
+													 "Enables QA features (logging, faster cycling) for metrics collector");
 
-		bool qa_mode(false);
-		if (gSavedSettings.getBOOL("QAMode") && metrics_submode)
+		if (metrics_submode)
 		{
+			app_metrics_qa_mode = true;
 			app_metrics_interval = METRICS_INTERVAL_QA;
-			qa_mode = true;
 		}
-		LLViewerAssetStatsFF::init(qa_mode);
+		LLViewerAssetStatsFF::init();
 	}
 
     initThreads();
@@ -1760,7 +1760,10 @@ bool LLAppViewer::initThreads()
 	// Image decoding
 	LLAppViewer::sImageDecodeThread = new LLImageDecodeThread(enable_threads && true);
 	LLAppViewer::sTextureCache = new LLTextureCache(enable_threads && true);
-	LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), sImageDecodeThread, enable_threads && true);
+	LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(),
+													sImageDecodeThread,
+													enable_threads && true,
+													app_metrics_qa_mode);
 	LLImage::initClass();
 
 	if (LLFastTimer::sLog || LLFastTimer::sMetricLog)
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index 8e43084adb..2e05a67791 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -1774,7 +1774,7 @@ bool LLTextureFetchWorker::writeToCacheComplete()
 //////////////////////////////////////////////////////////////////////////////
 // public
 
-LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded)
+LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded, bool qa_mode)
 	: LLWorkerThread("TextureFetch", threaded),
 	  mDebugCount(0),
 	  mDebugPause(FALSE),
@@ -1786,7 +1786,8 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image
 	  mImageDecodeThread(imagedecodethread),
 	  mTextureBandwidth(0),
 	  mHTTPTextureBits(0),
-	  mCurlGetRequest(NULL)
+	  mCurlGetRequest(NULL),
+	  mQAMode(qa_mode)
 {
 	mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS");
 	mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), gSavedSettings.getU32("TextureLoggingThreshold"));
@@ -2833,7 +2834,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
 	}
 
 	// In QA mode, Metrics submode, log the result for ease of testing
-	if (gViewerAssetStatsThread1->isQAMode())
+	if (fetcher->isQAMode())
 	{
 		LL_INFOS("QAViewerMetrics") << thread1_stats << LL_ENDL;
 	}
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index 88b7e4a16b..d46d2da7bc 100644
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -49,7 +49,7 @@ class LLTextureFetch : public LLWorkerThread
 	friend class HTTPGetResponder;
 	
 public:
-	LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded);
+	LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded, bool qa_mode);
 	~LLTextureFetch();
 
 	/*virtual*/ S32 update(U32 max_time_ms);	
@@ -90,8 +90,10 @@ public:
 	void commandSendMetrics(const std::string & caps_url, LLSD * report_main);
 	void commandDataBreak();
 
-	LLCurlRequest & getCurlRequest() { return *mCurlGetRequest; }
-	
+	LLCurlRequest & getCurlRequest()	{ return *mCurlGetRequest; }
+
+	bool isQAMode() const				{ return mQAMode; }
+
 protected:
 	void addToNetworkQueue(LLTextureFetchWorker* worker);
 	void removeFromNetworkQueue(LLTextureFetchWorker* worker, bool cancel);
@@ -109,8 +111,33 @@ private:
 	/*virtual*/ void threadedUpdate(void);
 
 	// Metrics command helpers
+	/**
+	 * Enqueues a command request at the end of the command queue
+	 * and wakes up the thread as needed.
+	 *
+	 * Takes ownership of the TFRequest object.
+	 *
+	 * Method locks the command queue.
+	 */
 	void cmdEnqueue(TFRequest *);
+
+	/**
+	 * Returns the first TFRequest object in the command queue or
+	 * NULL if none is present.
+	 *
+	 * Caller acquires ownership of the object and must dispose of it.
+	 *
+	 * Method locks the command queue.
+	 */
 	TFRequest * cmdDequeue();
+
+	/**
+	 * Processes the first command in the queue disposing of the
+	 * request on completion.  Successive calls are needed to perform
+	 * additional commands.
+	 *
+	 * Method locks the command queue.
+	 */
 	void cmdDoWork();
 	
 public:
@@ -151,6 +178,9 @@ private:
 	typedef std::vector<TFRequest *> command_queue_t;
 	command_queue_t mCommands;
 
+	// If true, modifies some behaviors that help with QA tasks.
+	const bool mQAMode;
+	
 public:
 	// A probabilistically-correct indicator that the current
 	// attempt to log metrics follows a break in the metrics stream
diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp
index a63c1bf66d..3d7f9f932f 100644
--- a/indra/newview/llviewerassetstats.cpp
+++ b/indra/newview/llviewerassetstats.cpp
@@ -129,8 +129,7 @@ LLViewerAssetStats::PerRegionStats::accumulateTime(duration_t now)
 // ------------------------------------------------------
 // LLViewerAssetStats class definition
 // ------------------------------------------------------
-LLViewerAssetStats::LLViewerAssetStats(bool qa_mode)
-	: mQAMode(qa_mode)
+LLViewerAssetStats::LLViewerAssetStats()
 {
 	reset();
 }
@@ -540,15 +539,15 @@ record_response_thread1(LLViewerAssetType::EType at, bool with_http, bool is_tem
 
 
 void
-init(bool qa_mode)
+init()
 {
 	if (! gViewerAssetStatsMain)
 	{
-		gViewerAssetStatsMain = new LLViewerAssetStats(qa_mode);
+		gViewerAssetStatsMain = new LLViewerAssetStats();
 	}
 	if (! gViewerAssetStatsThread1)
 	{
-		gViewerAssetStatsThread1 = new LLViewerAssetStats(qa_mode);
+		gViewerAssetStatsThread1 = new LLViewerAssetStats();
 	}
 }
 
diff --git a/indra/newview/llviewerassetstats.h b/indra/newview/llviewerassetstats.h
index 1668a1bc9d..b0fb17ae17 100644
--- a/indra/newview/llviewerassetstats.h
+++ b/indra/newview/llviewerassetstats.h
@@ -140,7 +140,7 @@ public:
 	};
 
 public:
-	LLViewerAssetStats(bool qa_mode);
+	LLViewerAssetStats();
 	// Default destructor is correct.
 	LLViewerAssetStats & operator=(const LLViewerAssetStats &);			// Not defined
 
@@ -197,10 +197,6 @@ public:
 	// final result is undefined (little defensive action).
 	static void mergeRegionsLLSD(const LLSD & src, LLSD & dst);
 
-	// QA mode is established during initialization so we don't
-	// touch LLSD at runtime.
-	bool isQAMode() const { return mQAMode; }
-	
 protected:
 	typedef std::map<LLUUID, LLPointer<PerRegionStats> > PerRegionContainer;
 
@@ -219,9 +215,6 @@ protected:
 
 	// Time of last reset
 	duration_t mResetTimestamp;
-
-	// QA Mode
-	const bool mQAMode;
 };
 
 
@@ -252,7 +245,7 @@ namespace LLViewerAssetStatsFF
  * you'll likely get away with calling it afterwards.  cleanup() should only be
  * called after threads are shutdown to prevent races on the global pointers.
  */
-void init(bool qa_mode);
+void init();
 
 void cleanup();
 
diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp
index 5a178fc585..a44712e8ad 100644
--- a/indra/newview/tests/llviewerassetstats_test.cpp
+++ b/indra/newview/tests/llviewerassetstats_test.cpp
@@ -133,7 +133,7 @@ namespace tut
 	{
 		ensure("Global gViewerAssetStatsMain should be NULL", (NULL == gViewerAssetStatsMain));
 
-		LLViewerAssetStats * it = new LLViewerAssetStats(false);
+		LLViewerAssetStats * it = new LLViewerAssetStats();
 
 		ensure("Global gViewerAssetStatsMain should still be NULL", (NULL == gViewerAssetStatsMain));
 
@@ -174,7 +174,7 @@ namespace tut
 	template<> template<>
 	void tst_viewerassetstats_index_object_t::test<3>()
 	{
-		LLViewerAssetStats * it = new LLViewerAssetStats(false);
+		LLViewerAssetStats * it = new LLViewerAssetStats();
 		it->setRegionID(region1);
 		
 		LLSD sd = it->asLLSD();
@@ -193,7 +193,7 @@ namespace tut
 	template<> template<>
 	void tst_viewerassetstats_index_object_t::test<4>()
 	{
-		gViewerAssetStatsMain = new LLViewerAssetStats(false);
+		gViewerAssetStatsMain = new LLViewerAssetStats();
 		LLViewerAssetStatsFF::set_region_main(region1);
 
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false);
@@ -230,8 +230,8 @@ namespace tut
 	template<> template<>
 	void tst_viewerassetstats_index_object_t::test<5>()
 	{
-		gViewerAssetStatsThread1 = new LLViewerAssetStats(false);
-		gViewerAssetStatsMain = new LLViewerAssetStats(false);
+		gViewerAssetStatsThread1 = new LLViewerAssetStats();
+		gViewerAssetStatsMain = new LLViewerAssetStats();
 		LLViewerAssetStatsFF::set_region_main(region1);
 
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false);
@@ -272,7 +272,7 @@ namespace tut
 	template<> template<>
 	void tst_viewerassetstats_index_object_t::test<6>()
 	{
-		gViewerAssetStatsMain = new LLViewerAssetStats(false);
+		gViewerAssetStatsMain = new LLViewerAssetStats();
 
 		LLViewerAssetStatsFF::set_region_main(region1);
 
@@ -329,7 +329,7 @@ namespace tut
 	template<> template<>
 	void tst_viewerassetstats_index_object_t::test<7>()
 	{
-		gViewerAssetStatsMain = new LLViewerAssetStats(false);
+		gViewerAssetStatsMain = new LLViewerAssetStats();
 
 		LLViewerAssetStatsFF::set_region_main(region1);
 
@@ -399,8 +399,8 @@ namespace tut
 	template<> template<>
 	void tst_viewerassetstats_index_object_t::test<8>()
 	{
-		gViewerAssetStatsThread1 = new LLViewerAssetStats(false);
-		gViewerAssetStatsMain = new LLViewerAssetStats(false);
+		gViewerAssetStatsThread1 = new LLViewerAssetStats();
+		gViewerAssetStatsMain = new LLViewerAssetStats();
 		LLViewerAssetStatsFF::set_region_main(region1);
 
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false);
-- 
cgit v1.2.3


From 6abc60be577bd29c2428d85143c8f583eab54723 Mon Sep 17 00:00:00 2001
From: Monty Brandenberg <monty@lindenlab.com>
Date: Tue, 23 Nov 2010 17:28:21 -0500
Subject: ESC-154 ESC-156 Viewer metrics Get the metrics message generation
 working in QAModeMetrics mode. Sample interval and data aren't correct yet
 but getting there.

---
 indra/newview/llappviewer.cpp | 50 +++++++++++++++++--------------------------
 1 file changed, 20 insertions(+), 30 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 07f4e71ebf..86fba90ff7 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -667,9 +667,9 @@ bool LLAppViewer::init()
 	
 	{
 		// Viewer metrics initialization
-		static LLCachedControl<BOOL> metrics_submode(gSavedSettings,
+		static LLCachedControl<bool> metrics_submode(gSavedSettings,
 													 "QAModeMetrics",
-													 FALSE,
+													 false,
 													 "Enables QA features (logging, faster cycling) for metrics collector");
 
 		if (metrics_submode)
@@ -4606,30 +4606,26 @@ void LLAppViewer::metricsIdle(bool enable_reporting)
 	if (! gViewerAssetStatsMain)
 		return;
 
-	std::string caps_url;
-	LLViewerRegion * regionp = gAgent.getRegion();
-	if (regionp)
+	if (LLAppViewer::sTextureFetch)
 	{
-		caps_url = regionp->getCapability("ViewerMetrics");
-	}
-	
-	if (enable_reporting && regionp && ! caps_url.empty())
-	{
-		// *NOTE:  Pay attention here.  LLSD's are not safe for thread sharing
-		// and their ownership is difficult to transfer across threads.  We do
-		// it here by having only one reference (the new'd pointer) to the LLSD
-		// or any subtree of it.  This pointer is then transfered to the other
-		// thread using correct thread logic.
-		
-		LLSD * envelope = new LLSD(LLSD::emptyMap());
+		LLViewerRegion * regionp = gAgent.getRegion();
+
+		if (enable_reporting && regionp)
 		{
-			(*envelope) = gViewerAssetStatsMain->asLLSD();
-			(*envelope)["session_id"] = gAgentSessionID;
-			(*envelope)["agent_id"] = gAgentID;
-		}
+			std::string	caps_url = regionp->getCapability("ViewerMetrics");
+
+			// *NOTE:  Pay attention here.  LLSD's are not safe for thread sharing
+			// and their ownership is difficult to transfer across threads.  We do
+			// it here by having only one reference (the new'd pointer) to the LLSD
+			// or any subtree of it.  This pointer is then transfered to the other
+			// thread using correct thread logic to do all data ordering.
+			LLSD * envelope = new LLSD(LLSD::emptyMap());
+			{
+				(*envelope) = gViewerAssetStatsMain->asLLSD();
+				(*envelope)["session_id"] = gAgentSessionID;
+				(*envelope)["agent_id"] = gAgentID;
+			}
 		
-		if (LLAppViewer::sTextureFetch)
-		{
 			// Send a report request into 'thread1' to get the rest of the data
 			// and have it sent to the stats collector.  LLSD ownership transfers
 			// with this call.
@@ -4638,15 +4634,9 @@ void LLAppViewer::metricsIdle(bool enable_reporting)
 		}
 		else
 		{
-			// No 'thread1' so transfer doesn't happen and we need to clean up
-			delete envelope;
-			envelope = 0;
+			LLAppViewer::sTextureFetch->commandDataBreak();
 		}
 	}
-	else
-	{
-		LLAppViewer::sTextureFetch->commandDataBreak();
-	}
 
 	// Reset even if we can't report.  Rather than gather up a huge chunk of
 	// data, we'll keep to our sampling interval and retain the data
-- 
cgit v1.2.3


From 0fd80d09972657e6417193abf577084a3b3b85f1 Mon Sep 17 00:00:00 2001
From: Monty Brandenberg <monty@lindenlab.com>
Date: Wed, 24 Nov 2010 16:46:40 -0500
Subject: ESC-154 ESC-156  Metrics integration across threads Using unpause()
 method in derived class rather than wake() in furthest base class solved the
 stalling problem.  I still think too many levels of the LLTextureFetch
 hierarchy are keeping thread state, however.  The LLViewerRegion instance an
 agent enters doesn't necessarily have its region_id yet, that only comes
 after the handshake, if any.  So add a few more metrics insertion points to
 propagate region into metrics. Finally, try to launch a final metrics report
 when a quit is initiated.

---
 indra/newview/llappviewer.cpp    |  5 +++--
 indra/newview/llappviewer.h      |  2 +-
 indra/newview/lltexturefetch.cpp | 37 ++++++++++++++++++++-----------------
 indra/newview/lltexturefetch.h   |  1 +
 indra/newview/llviewerregion.cpp |  8 ++++++++
 5 files changed, 33 insertions(+), 20 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 86fba90ff7..bf79523078 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2932,6 +2932,7 @@ void LLAppViewer::requestQuit()
 	LLSideTray::getInstance()->notifyChildren(LLSD().with("request","quit"));
 
 	send_stats();
+	metricsSend(!gDisconnected);
 
 	gLogoutTimer.reset();
 	mQuitRequested = true;
@@ -3719,7 +3720,7 @@ void LLAppViewer::idle()
 		// *TODO:  Add configuration controls for this
 		if (report_interval.getElapsedTimeF32() >= app_metrics_interval)
 		{
-			metricsIdle(! gDisconnected);
+			metricsSend(! gDisconnected);
 			report_interval.reset();
 		}
 	}
@@ -4601,7 +4602,7 @@ void LLAppViewer::metricsUpdateRegion(const LLUUID & region_id)
  * Attempts to start a multi-threaded metrics report to be sent back to
  * the grid for consumption.
  */
-void LLAppViewer::metricsIdle(bool enable_reporting)
+void LLAppViewer::metricsSend(bool enable_reporting)
 {
 	if (! gViewerAssetStatsMain)
 		return;
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 909f191ab1..27c104626a 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -170,7 +170,7 @@ public:
 
 	// Metrics policy helper statics.
 	static void metricsUpdateRegion(const LLUUID & region_id);
-	static void metricsIdle(bool enable_reporting);
+	static void metricsSend(bool enable_reporting);
 	
 protected:
 	virtual bool initWindow(); // Initialize the viewer's window.
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index 2e05a67791..2be3ba3280 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -2105,6 +2105,21 @@ bool LLTextureFetch::runCondition()
 
 //////////////////////////////////////////////////////////////////////////////
 
+// MAIN THREAD (unthreaded envs), WORKER THREAD (threaded envs)
+void LLTextureFetch::commonUpdate()
+{
+	// Run a cross-thread command, if any.
+	cmdDoWork();
+	
+	// Update Curl on same thread as mCurlGetRequest was constructed
+	S32 processed = mCurlGetRequest->process();
+	if (processed > 0)
+	{
+		lldebugs << "processed: " << processed << " messages." << llendl;
+	}	
+}
+
+
 // MAIN THREAD
 //virtual
 S32 LLTextureFetch::update(U32 max_time_ms)
@@ -2130,12 +2145,7 @@ S32 LLTextureFetch::update(U32 max_time_ms)
 
 	if (!mThreaded)
 	{
-		// Update Curl on same thread as mCurlGetRequest was constructed
-		S32 processed = mCurlGetRequest->process();
-		if (processed > 0)
-		{
-			lldebugs << "processed: " << processed << " messages." << llendl;
-		}
+		commonUpdate();
 	}
 
 	return res;
@@ -2190,15 +2200,7 @@ void LLTextureFetch::threadedUpdate()
 	}
 	process_timer.reset();
 	
-	// Run a cross-thread command, if any.
-	cmdDoWork();
-	
-	// Update Curl on same thread as mCurlGetRequest was constructed
-	S32 processed = mCurlGetRequest->process();
-	if (processed > 0)
-	{
-		lldebugs << "processed: " << processed << " messages." << llendl;
-	}
+	commonUpdate();
 
 #if 0
 	const F32 INFO_TIME = 1.0f; 
@@ -2657,6 +2659,7 @@ void LLTextureFetch::commandSetRegion(const LLUUID & region_id)
 	TFReqSetRegion * req = new TFReqSetRegion(region_id);
 
 	cmdEnqueue(req);
+	LL_INFOS("Texture") << "COMMANDING SET REGION" << LL_ENDL;
 }
 
 void LLTextureFetch::commandSendMetrics(const std::string & caps_url,
@@ -2683,7 +2686,7 @@ void LLTextureFetch::cmdEnqueue(TFRequest * req)
 	mCommands.push_back(req);
 	unlockQueue();
 
-	wake();
+	unpause();
 }
 
 TFRequest * LLTextureFetch::cmdDequeue()
@@ -2818,7 +2821,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
 	LLViewerAssetStatsFF::merge_stats(main_stats, thread1_stats);
 
 	// *TODO:  Consider putting a report size limiter here.
-
+	LL_INFOS("Texture") << "PROCESSING SENDMETRICS REQUEST" << LL_ENDL;
 	if (! mCapsURL.empty())
 	{
 		LLCurlRequest::headers_t headers;
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index d46d2da7bc..bad0a1498f 100644
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -109,6 +109,7 @@ private:
 	/*virtual*/ void startThread(void);
 	/*virtual*/ void endThread(void);
 	/*virtual*/ void threadedUpdate(void);
+	void commonUpdate();
 
 	// Metrics command helpers
 	/**
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 79b45a459f..717ef40465 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -1341,6 +1341,14 @@ void LLViewerRegion::unpackRegionHandshake()
 	msg->nextBlock("RegionInfo");
 	msg->addU32("Flags", 0x0 );
 	msg->sendReliable(host);
+
+	// Inform metrics when a region associated with an agent
+	// receives a regionID.
+	if (gAgent.getRegion() == this)
+	{
+		// Region is active in agent, tell metrics about the region ID
+		LLAppViewer::metricsUpdateRegion(region_id);
+	}
 }
 
 void LLViewerRegion::setSeedCapability(const std::string& url)
-- 
cgit v1.2.3


From a4bf7322895cac318abc3ac0a000086d227fc2fe Mon Sep 17 00:00:00 2001
From: Monty Brandenberg <monty@lindenlab.com>
Date: Wed, 24 Nov 2010 15:02:46 -0800
Subject: ESC-154 ESC-155 Viewer metrics fixes for min/max merged values,
 floating timestamps. The min/max response time calculations needed to be
 sensitive to the response counts to know if their was actual data.  Failure
 to do so introduced a gratuitous min/max test against zero values which
 tended to corrupt the mins.  Unit tests added to test for this condition. 
 Finished conversion of times to floating point seconds.  Removed two logging
 events used to debug the cross-thread messaging.  Looks like a code
 completion point.

---
 indra/newview/lltexturefetch.cpp                |   4 +-
 indra/newview/llviewerassetstats.cpp            |  60 +++++--
 indra/newview/tests/llviewerassetstats_test.cpp | 228 ++++++++++++++++++++++++
 3 files changed, 271 insertions(+), 21 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index 2be3ba3280..f5e2e35e1e 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -2659,7 +2659,6 @@ void LLTextureFetch::commandSetRegion(const LLUUID & region_id)
 	TFReqSetRegion * req = new TFReqSetRegion(region_id);
 
 	cmdEnqueue(req);
-	LL_INFOS("Texture") << "COMMANDING SET REGION" << LL_ENDL;
 }
 
 void LLTextureFetch::commandSendMetrics(const std::string & caps_url,
@@ -2821,7 +2820,6 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
 	LLViewerAssetStatsFF::merge_stats(main_stats, thread1_stats);
 
 	// *TODO:  Consider putting a report size limiter here.
-	LL_INFOS("Texture") << "PROCESSING SENDMETRICS REQUEST" << LL_ENDL;
 	if (! mCapsURL.empty())
 	{
 		LLCurlRequest::headers_t headers;
@@ -2839,7 +2837,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
 	// In QA mode, Metrics submode, log the result for ease of testing
 	if (fetcher->isQAMode())
 	{
-		LL_INFOS("QAViewerMetrics") << thread1_stats << LL_ENDL;
+		LL_INFOS("Textures") << thread1_stats << LL_ENDL;
 	}
 
 	gViewerAssetStatsThread1->reset();
diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp
index 3d7f9f932f..502a3aa340 100644
--- a/indra/newview/llviewerassetstats.cpp
+++ b/indra/newview/llviewerassetstats.cpp
@@ -263,19 +263,19 @@ LLViewerAssetStats::asLLSD()
 			slot[enq_tag] = LLSD(S32(stats.mRequests[i].mEnqueued.getCount()));
 			slot[deq_tag] = LLSD(S32(stats.mRequests[i].mDequeued.getCount()));
 			slot[rcnt_tag] = LLSD(S32(stats.mRequests[i].mResponse.getCount()));
-			slot[rmin_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMin()));
-			slot[rmax_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMax()));
-			slot[rmean_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMean()));
+			slot[rmin_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMin() * 1.0e-6));
+			slot[rmax_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMax() * 1.0e-6));
+			slot[rmean_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMean() * 1.0e-6));
 		}
 
-		reg_stat["duration"] = LLSD::Integer(stats.mTotalTime / 1000000);
+		reg_stat["duration"] = LLSD::Real(stats.mTotalTime * 1.0e-6);
 		
 		regions[it->first.asString()] = reg_stat;
 	}
 
 	LLSD ret = LLSD::emptyMap();
 	ret["regions"] = regions;
-	ret["duration"] = LLSD::Integer((now - mResetTimestamp) / 1000000);
+	ret["duration"] = LLSD::Real((now - mResetTimestamp) * 1.0e-6);
 	
 	return ret;
 }
@@ -290,12 +290,12 @@ LLViewerAssetStats::mergeRegionsLLSD(const LLSD & src, LLSD & dst)
 	static const int MOP_MEAN_REAL(3);	// Requires a 'mMergeOpArg' to weight the input terms
 
 	static const LLSD::String regions_key("regions");
+	static const LLSD::String resp_count_key("resp_count");
 	
 	static const struct
 		{
 			LLSD::String		mName;
 			int					mMergeOp;
-			LLSD::String		mMergeOpArg;
 		}
 	key_list[] =
 		{
@@ -305,12 +305,12 @@ LLViewerAssetStats::mergeRegionsLLSD(const LLSD & src, LLSD & dst)
 			// is modified or the weight will be wrong.  Key list is
 			// defined in asLLSD() and must track it.
 
-			{ "resp_mean", MOP_MEAN_REAL, "resp_count" },
-			{ "enqueued", MOP_ADD_INT, "" },
-			{ "dequeued", MOP_ADD_INT, "" },
-			{ "resp_count", MOP_ADD_INT, "" },
-			{ "resp_min", MOP_MIN_REAL, "" },
-			{ "resp_max", MOP_MAX_REAL, "" }
+			{ "resp_mean", MOP_MEAN_REAL },
+			{ "enqueued", MOP_ADD_INT },
+			{ "dequeued", MOP_ADD_INT },
+			{ "resp_min", MOP_MIN_REAL },
+			{ "resp_max", MOP_MAX_REAL },
+			{ resp_count_key, MOP_ADD_INT }			// Keep last
 		};
 
 	// Trivial checks
@@ -368,6 +368,10 @@ LLViewerAssetStats::mergeRegionsLLSD(const LLSD & src, LLSD & dst)
 					LLSD & bin_dst(reg_dst[it_sets->first]);
 					const LLSD & bin_src(reg_src[it_sets->first]);
 
+					// The "resp_count" value is needed repeatedly in operations.
+					const LLSD::Integer bin_src_count(bin_src[resp_count_key].asInteger());
+					const LLSD::Integer bin_dst_count(bin_dst[resp_count_key].asInteger());
+			
 					for (int key_index(0); key_index < LL_ARRAY_SIZE(key_list); ++key_index)
 					{
 						const LLSD::String & key_name(key_list[key_index].mName);
@@ -395,25 +399,45 @@ LLViewerAssetStats::mergeRegionsLLSD(const LLSD & src, LLSD & dst)
 							case MOP_ADD_INT:
 								// Simple counts, just add
 								dst_value = dst_value.asInteger() + src_value.asInteger();
-						
 								break;
 						
 							case MOP_MIN_REAL:
 								// Minimum
-								dst_value = llmin(dst_value.asReal(), src_value.asReal());
+								if (bin_src_count)
+								{
+									// If src has non-zero count, it's min is meaningful
+									if (bin_dst_count)
+									{
+										dst_value = llmin(dst_value.asReal(), src_value.asReal());
+									}
+									else
+									{
+										dst_value = src_value;
+									}
+								}
 								break;
 
 							case MOP_MAX_REAL:
 								// Maximum
-								dst_value = llmax(dst_value.asReal(), src_value.asReal());
+								if (bin_src_count)
+								{
+									// If src has non-zero count, it's max is meaningful
+									if (bin_dst_count)
+									{
+										dst_value = llmax(dst_value.asReal(), src_value.asReal());
+									}
+									else
+									{
+										dst_value = src_value;
+									}
+								}
 								break;
 
 							case MOP_MEAN_REAL:
 							    {
 									// Mean
-									const LLSD::String & weight_key(key_list[key_index].mMergeOpArg);
-									F64 src_weight(bin_src[weight_key].asReal());
-									F64 dst_weight(bin_dst[weight_key].asReal());
+									F64 src_weight(bin_src_count);
+									F64 dst_weight(bin_dst_count);
 									F64 tot_weight(src_weight + dst_weight);
 									if (tot_weight >= F64(0.5))
 									{
diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp
index a44712e8ad..8bedd2c860 100644
--- a/indra/newview/tests/llviewerassetstats_test.cpp
+++ b/indra/newview/tests/llviewerassetstats_test.cpp
@@ -518,4 +518,232 @@ namespace tut
 			ensure_approximately_equals("weighted mean of means", dst["regions"][reg1_name]["get_other"]["resp_mean"].asReal(), 2.7901295, 20);
 		}
 	}
+
+	// Maximum merges are interesting when one side contributes nothing
+	template<> template<>
+	void tst_viewerassetstats_index_object_t::test<10>()
+	{
+		LLSD::String reg1_name = region1.asString();
+		LLSD::String reg2_name = region2.asString();
+
+		LLSD reg1_stats = LLSD::emptyMap();
+		LLSD reg2_stats = LLSD::emptyMap();
+
+		LLSD & tmp_other1 = reg1_stats["get_other"];
+		tmp_other1["enqueued"] = 4;
+		tmp_other1["dequeued"] = 4;
+		tmp_other1["resp_count"] = 7;
+		tmp_other1["resp_max"] = F64(-23.2892);
+		tmp_other1["resp_min"] = F64(-123.2892);
+		tmp_other1["resp_mean"] = F64(-58.28298);
+
+		LLSD & tmp_other2 = reg2_stats["get_other"];
+		tmp_other2["enqueued"] = 8;
+		tmp_other2["dequeued"] = 7;
+		tmp_other2["resp_count"] = 0;
+		tmp_other2["resp_max"] = F64(0);
+		tmp_other2["resp_min"] = F64(0);
+		tmp_other2["resp_mean"] = F64(0);
+		
+		{
+			LLSD src = LLSD::emptyMap();
+			LLSD dst = LLSD::emptyMap();
+
+			src["regions"][reg1_name] = reg1_stats;
+			src["duration"] = 24;
+			dst["regions"][reg1_name] = reg2_stats;
+			dst["duration"] = 36;
+
+			LLViewerAssetStats::mergeRegionsLLSD(src, dst);
+		
+			ensure_approximately_equals("dst maximum with count 0 does not contribute to merged maximum",
+										dst["regions"][reg1_name]["get_other"]["resp_max"].asReal(), F64(-23.2892), 20);
+		}
+
+		{
+			LLSD src = LLSD::emptyMap();
+			LLSD dst = LLSD::emptyMap();
+
+			src["regions"][reg1_name] = reg2_stats;
+			src["duration"] = 24;
+			dst["regions"][reg1_name] = reg1_stats;
+			dst["duration"] = 36;
+
+			LLViewerAssetStats::mergeRegionsLLSD(src, dst);
+		
+			ensure_approximately_equals("src maximum with count 0 does not contribute to merged maximum",
+										dst["regions"][reg1_name]["get_other"]["resp_max"].asReal(), F64(-23.2892), 20);
+		}
+	}
+
+    // Minimum merges are interesting when one side contributes nothing
+	template<> template<>
+	void tst_viewerassetstats_index_object_t::test<11>()
+	{
+		LLSD::String reg1_name = region1.asString();
+		LLSD::String reg2_name = region2.asString();
+
+		LLSD reg1_stats = LLSD::emptyMap();
+		LLSD reg2_stats = LLSD::emptyMap();
+
+		LLSD & tmp_other1 = reg1_stats["get_other"];
+		tmp_other1["enqueued"] = 4;
+		tmp_other1["dequeued"] = 4;
+		tmp_other1["resp_count"] = 7;
+		tmp_other1["resp_max"] = F64(123.2892);
+		tmp_other1["resp_min"] = F64(23.2892);
+		tmp_other1["resp_mean"] = F64(58.28298);
+
+		LLSD & tmp_other2 = reg2_stats["get_other"];
+		tmp_other2["enqueued"] = 8;
+		tmp_other2["dequeued"] = 7;
+		tmp_other2["resp_count"] = 0;
+		tmp_other2["resp_max"] = F64(0);
+		tmp_other2["resp_min"] = F64(0);
+		tmp_other2["resp_mean"] = F64(0);
+		
+		{
+			LLSD src = LLSD::emptyMap();
+			LLSD dst = LLSD::emptyMap();
+
+			src["regions"][reg1_name] = reg1_stats;
+			src["duration"] = 24;
+			dst["regions"][reg1_name] = reg2_stats;
+			dst["duration"] = 36;
+
+			LLViewerAssetStats::mergeRegionsLLSD(src, dst);
+		
+			ensure_approximately_equals("dst minimum with count 0 does not contribute to merged minimum",
+										dst["regions"][reg1_name]["get_other"]["resp_min"].asReal(), F64(23.2892), 20);
+		}
+
+		{
+			LLSD src = LLSD::emptyMap();
+			LLSD dst = LLSD::emptyMap();
+
+			src["regions"][reg1_name] = reg2_stats;
+			src["duration"] = 24;
+			dst["regions"][reg1_name] = reg1_stats;
+			dst["duration"] = 36;
+
+			LLViewerAssetStats::mergeRegionsLLSD(src, dst);
+		
+			ensure_approximately_equals("src minimum with count 0 does not contribute to merged minimum",
+										dst["regions"][reg1_name]["get_other"]["resp_min"].asReal(), F64(23.2892), 20);
+		}
+	}
+
+    // resp_count missing is taken as '0' for maximum calculation
+	template<> template<>
+	void tst_viewerassetstats_index_object_t::test<12>()
+	{
+		LLSD::String reg1_name = region1.asString();
+		LLSD::String reg2_name = region2.asString();
+
+		LLSD reg1_stats = LLSD::emptyMap();
+		LLSD reg2_stats = LLSD::emptyMap();
+
+		LLSD & tmp_other1 = reg1_stats["get_other"];
+		tmp_other1["enqueued"] = 4;
+		tmp_other1["dequeued"] = 4;
+		tmp_other1["resp_count"] = 7;
+		tmp_other1["resp_max"] = F64(-23.2892);
+		tmp_other1["resp_min"] = F64(-123.2892);
+		tmp_other1["resp_mean"] = F64(-58.28298);
+
+		LLSD & tmp_other2 = reg2_stats["get_other"];
+		tmp_other2["enqueued"] = 8;
+		tmp_other2["dequeued"] = 7;
+		// tmp_other2["resp_count"] = 0;
+		tmp_other2["resp_max"] = F64(0);
+		tmp_other2["resp_min"] = F64(0);
+		tmp_other2["resp_mean"] = F64(0);
+		
+		{
+			LLSD src = LLSD::emptyMap();
+			LLSD dst = LLSD::emptyMap();
+
+			src["regions"][reg1_name] = reg1_stats;
+			src["duration"] = 24;
+			dst["regions"][reg1_name] = reg2_stats;
+			dst["duration"] = 36;
+
+			LLViewerAssetStats::mergeRegionsLLSD(src, dst);
+		
+			ensure_approximately_equals("dst maximum with undefined count does not contribute to merged maximum",
+										dst["regions"][reg1_name]["get_other"]["resp_max"].asReal(), F64(-23.2892), 20);
+		}
+
+		{
+			LLSD src = LLSD::emptyMap();
+			LLSD dst = LLSD::emptyMap();
+
+			src["regions"][reg1_name] = reg2_stats;
+			src["duration"] = 24;
+			dst["regions"][reg1_name] = reg1_stats;
+			dst["duration"] = 36;
+
+			LLViewerAssetStats::mergeRegionsLLSD(src, dst);
+		
+			ensure_approximately_equals("src maximum with undefined count does not contribute to merged maximum",
+										dst["regions"][reg1_name]["get_other"]["resp_max"].asReal(), F64(-23.2892), 20);
+		}
+	}
+
+    // resp_count unspecified is taken as 0 for minimum merges
+	template<> template<>
+	void tst_viewerassetstats_index_object_t::test<13>()
+	{
+		LLSD::String reg1_name = region1.asString();
+		LLSD::String reg2_name = region2.asString();
+
+		LLSD reg1_stats = LLSD::emptyMap();
+		LLSD reg2_stats = LLSD::emptyMap();
+
+		LLSD & tmp_other1 = reg1_stats["get_other"];
+		tmp_other1["enqueued"] = 4;
+		tmp_other1["dequeued"] = 4;
+		tmp_other1["resp_count"] = 7;
+		tmp_other1["resp_max"] = F64(123.2892);
+		tmp_other1["resp_min"] = F64(23.2892);
+		tmp_other1["resp_mean"] = F64(58.28298);
+
+		LLSD & tmp_other2 = reg2_stats["get_other"];
+		tmp_other2["enqueued"] = 8;
+		tmp_other2["dequeued"] = 7;
+		// tmp_other2["resp_count"] = 0;
+		tmp_other2["resp_max"] = F64(0);
+		tmp_other2["resp_min"] = F64(0);
+		tmp_other2["resp_mean"] = F64(0);
+		
+		{
+			LLSD src = LLSD::emptyMap();
+			LLSD dst = LLSD::emptyMap();
+
+			src["regions"][reg1_name] = reg1_stats;
+			src["duration"] = 24;
+			dst["regions"][reg1_name] = reg2_stats;
+			dst["duration"] = 36;
+
+			LLViewerAssetStats::mergeRegionsLLSD(src, dst);
+		
+			ensure_approximately_equals("dst minimum with undefined count does not contribute to merged minimum",
+										dst["regions"][reg1_name]["get_other"]["resp_min"].asReal(), F64(23.2892), 20);
+		}
+
+		{
+			LLSD src = LLSD::emptyMap();
+			LLSD dst = LLSD::emptyMap();
+
+			src["regions"][reg1_name] = reg2_stats;
+			src["duration"] = 24;
+			dst["regions"][reg1_name] = reg1_stats;
+			dst["duration"] = 36;
+
+			LLViewerAssetStats::mergeRegionsLLSD(src, dst);
+		
+			ensure_approximately_equals("src minimum with undefined count does not contribute to merged minimum",
+										dst["regions"][reg1_name]["get_other"]["resp_min"].asReal(), F64(23.2892), 20);
+		}
+	}
 }
-- 
cgit v1.2.3


From 0f2ed092c5712cd5dcd928e079671df383227068 Mon Sep 17 00:00:00 2001
From: Monty Brandenberg <monty@lindenlab.com>
Date: Mon, 29 Nov 2010 08:31:08 -0800
Subject: ESC-154 ESC-156 Now using region hash rather than region uuid as
 identifier. In the viewer, the region's UUID is acquired very late and isn't
 generally used as the canonical region identifier.  The U64 region hash is a
 better and more consistently used identifier so I'm moving over to using that
 as the region key.  Don't have a proper reserved invalid region hash which is
 unfortunate, but then, so much is.

---
 indra/newview/llagent.cpp                       |  2 +-
 indra/newview/llappviewer.cpp                   | 10 +--
 indra/newview/llappviewer.h                     |  2 +-
 indra/newview/lltexturefetch.cpp                | 18 ++---
 indra/newview/lltexturefetch.h                  |  2 +-
 indra/newview/llviewerassetstats.cpp            | 36 +++++-----
 indra/newview/llviewerassetstats.h              | 31 +++++----
 indra/newview/llviewerregion.cpp                |  8 ---
 indra/newview/tests/llviewerassetstats_test.cpp | 88 +++++++++++++------------
 9 files changed, 102 insertions(+), 95 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index e2b1c89402..d5eec0e151 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -639,7 +639,7 @@ void LLAgent::setRegion(LLViewerRegion *regionp)
 		}
 
 		// Pass new region along to metrics components that care about this level of detail.
-		LLAppViewer::metricsUpdateRegion(regionp->getRegionID());
+		LLAppViewer::metricsUpdateRegion(regionp->getHandle());
 	}
 	mRegionp = regionp;
 
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index bf79523078..d73f3cd2fc 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -4579,20 +4579,20 @@ bool LLAppViewer::getMasterSystemAudioMute()
  * on the main thread, we need to send a message to move the data over safely
  * and cheaply (amortized over a run).
  */
-void LLAppViewer::metricsUpdateRegion(const LLUUID & region_id)
+void LLAppViewer::metricsUpdateRegion(U64 region_handle)
 {
-	if (! region_id.isNull())
+	if (0 != region_handle)
 	{
-		LLViewerAssetStatsFF::set_region_main(region_id);
+		LLViewerAssetStatsFF::set_region_main(region_handle);
 		if (LLAppViewer::sTextureFetch)
 		{
 			// Send a region update message into 'thread1' to get the new region.
-			LLAppViewer::sTextureFetch->commandSetRegion(region_id);
+			LLAppViewer::sTextureFetch->commandSetRegion(region_handle);
 		}
 		else
 		{
 			// No 'thread1', a.k.a. TextureFetch, so update directly
-			LLViewerAssetStatsFF::set_region_thread1(region_id);
+			LLViewerAssetStatsFF::set_region_thread1(region_handle);
 		}
 	}
 }
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 27c104626a..6b83f2d80c 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -169,7 +169,7 @@ public:
 	virtual bool getMasterSystemAudioMute();
 
 	// Metrics policy helper statics.
-	static void metricsUpdateRegion(const LLUUID & region_id);
+	static void metricsUpdateRegion(U64 region_handle);
 	static void metricsSend(bool enable_reporting);
 	
 protected:
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index f5e2e35e1e..3793085e55 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -506,9 +506,9 @@ public:
 class TFReqSetRegion : public TFRequest
 {
 public:
-	TFReqSetRegion(const LLUUID & region_id)
+	TFReqSetRegion(U64 region_handle)
 		: TFRequest(),
-		  mRegionID(region_id)
+		  mRegionHandle(region_handle)
 		{}
 	TFReqSetRegion & operator=(const TFReqSetRegion &);	// Not defined
 
@@ -518,7 +518,7 @@ public:
 	virtual bool doWork(LLTextureFetch * fetcher);
 		
 public:
-	const LLUUID mRegionID;
+	const U64 mRegionHandle;
 };
 
 
@@ -2654,9 +2654,9 @@ void LLTextureFetch::dump()
 
 // cross-thread command methods
 
-void LLTextureFetch::commandSetRegion(const LLUUID & region_id)
+void LLTextureFetch::commandSetRegion(U64 region_handle)
 {
-	TFReqSetRegion * req = new TFReqSetRegion(region_id);
+	TFReqSetRegion * req = new TFReqSetRegion(region_handle);
 
 	cmdEnqueue(req);
 }
@@ -2735,7 +2735,7 @@ namespace
 bool
 TFReqSetRegion::doWork(LLTextureFetch *)
 {
-	LLViewerAssetStatsFF::set_region_thread1(mRegionID);
+	LLViewerAssetStatsFF::set_region_thread1(mRegionHandle);
 
 	return true;
 }
@@ -2806,9 +2806,9 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
 	// still being careful, regardless.
 	LLSD & main_stats = *mReportMain;
 
-	LLSD thread1_stats = gViewerAssetStatsThread1->asLLSD();			// 'duration' & 'regions' from here
-	thread1_stats["message"] = "ViewerAssetMetrics";
-	thread1_stats["sequence"] = report_sequence;
+	LLSD thread1_stats = gViewerAssetStatsThread1->asLLSD();			// 'duration' & 'regions' from this LLSD
+	thread1_stats["message"] = "ViewerAssetMetrics";					// Identifies the type of metrics
+	thread1_stats["sequence"] = report_sequence;						// Sequence number
 	thread1_stats["initial"] = ! reporting_started;						// Initial data from viewer
 	thread1_stats["break"] = LLTextureFetch::svMetricsDataBreak;		// Break in data prior to this report
 		
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index bad0a1498f..03e2462058 100644
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -86,7 +86,7 @@ public:
 	LLTextureInfo* getTextureInfo() { return &mTextureInfo; }
 
 	// Commands available to other threads to control metrics gathering operations.
-	void commandSetRegion(const LLUUID & region_id);
+	void commandSetRegion(U64 region_handle);
 	void commandSendMetrics(const std::string & caps_url, LLSD * report_main);
 	void commandDataBreak();
 
diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp
index 502a3aa340..cc41a95893 100644
--- a/indra/newview/llviewerassetstats.cpp
+++ b/indra/newview/llviewerassetstats.cpp
@@ -130,6 +130,7 @@ LLViewerAssetStats::PerRegionStats::accumulateTime(duration_t now)
 // LLViewerAssetStats class definition
 // ------------------------------------------------------
 LLViewerAssetStats::LLViewerAssetStats()
+	: mRegionHandle(U64(0))
 {
 	reset();
 }
@@ -149,11 +150,11 @@ LLViewerAssetStats::reset()
 	}
 	else
 	{
-		mCurRegionStats = new PerRegionStats(mRegionID);
+		mCurRegionStats = new PerRegionStats(mRegionHandle);
 	}
 
 	// And add reference to map
-	mRegionStats[mRegionID] = mCurRegionStats;
+	mRegionStats[mRegionHandle] = mCurRegionStats;
 
 	// Start timestamp consistent with per-region collector
 	mResetTimestamp = mCurRegionStats->mStartTimestamp;
@@ -161,9 +162,9 @@ LLViewerAssetStats::reset()
 
 
 void
-LLViewerAssetStats::setRegionID(const LLUUID & region_id)
+LLViewerAssetStats::setRegion(region_handle_t region_handle)
 {
-	if (region_id == mRegionID)
+	if (region_handle == mRegionHandle)
 	{
 		// Already active, ignore.
 		return;
@@ -174,19 +175,19 @@ LLViewerAssetStats::setRegionID(const LLUUID & region_id)
 	mCurRegionStats->accumulateTime(now);
 
 	// Prepare new set
-	PerRegionContainer::iterator new_stats = mRegionStats.find(region_id);
+	PerRegionContainer::iterator new_stats = mRegionStats.find(region_handle);
 	if (mRegionStats.end() == new_stats)
 	{
 		// Haven't seen this region_id before, create a new block and make it current.
-		mCurRegionStats = new PerRegionStats(region_id);
-		mRegionStats[region_id] = mCurRegionStats;
+		mCurRegionStats = new PerRegionStats(region_handle);
+		mRegionStats[region_handle] = mCurRegionStats;
 	}
 	else
 	{
 		mCurRegionStats = new_stats->second;
 	}
 	mCurRegionStats->mStartTimestamp = now;
-	mRegionID = region_id;
+	mRegionHandle = region_handle;
 }
 
 
@@ -245,9 +246,9 @@ LLViewerAssetStats::asLLSD()
 		 mRegionStats.end() != it;
 		 ++it)
 	{
-		if (it->first.isNull())
+		if (0 == it->first)
 		{
-			// Never emit NULL UUID in results.
+			// Never emit NULL UUID/handle in results.
 			continue;
 		}
 
@@ -269,8 +270,11 @@ LLViewerAssetStats::asLLSD()
 		}
 
 		reg_stat["duration"] = LLSD::Real(stats.mTotalTime * 1.0e-6);
-		
-		regions[it->first.asString()] = reg_stat;
+		std::stringstream reg_handle;
+		reg_handle.width(16);
+		reg_handle.fill('0');
+		reg_handle << std::hex << it->first;
+		regions[reg_handle.str()] = reg_stat;
 	}
 
 	LLSD ret = LLSD::emptyMap();
@@ -487,12 +491,12 @@ namespace LLViewerAssetStatsFF
 // 'main' thread - initial program thread
 
 void
-set_region_main(const LLUUID & region_id)
+set_region_main(LLViewerAssetStats::region_handle_t region_handle)
 {
 	if (! gViewerAssetStatsMain)
 		return;
 
-	gViewerAssetStatsMain->setRegionID(region_id);
+	gViewerAssetStatsMain->setRegion(region_handle);
 }
 
 void
@@ -526,12 +530,12 @@ record_response_main(LLViewerAssetType::EType at, bool with_http, bool is_temp,
 // 'thread1' - should be for TextureFetch thread
 
 void
-set_region_thread1(const LLUUID & region_id)
+set_region_thread1(LLViewerAssetStats::region_handle_t region_handle)
 {
 	if (! gViewerAssetStatsThread1)
 		return;
 
-	gViewerAssetStatsThread1->setRegionID(region_id);
+	gViewerAssetStatsThread1->setRegion(region_handle);
 }
 
 void
diff --git a/indra/newview/llviewerassetstats.h b/indra/newview/llviewerassetstats.h
index b0fb17ae17..ed2d0f3922 100644
--- a/indra/newview/llviewerassetstats.h
+++ b/indra/newview/llviewerassetstats.h
@@ -101,7 +101,14 @@ public:
 	 * fetcher class, LLTextureFetch.
 	 */
 	typedef U64 duration_t;
-	
+
+	/**
+	 * Type for the region identifier used in stats.  Currently uses
+	 * the region handle's type (a U64) rather than the regions's LLUUID
+	 * as the latter isn't available immediately.
+	 */
+	typedef U64 region_handle_t;
+
 	/**
 	 * @brief Collected data for a single region visited by the avatar.
 	 *
@@ -112,9 +119,9 @@ public:
 	class PerRegionStats : public LLRefCount
 	{
 	public:
-		PerRegionStats(const LLUUID & region_id)
+		PerRegionStats(const region_handle_t region_handle)
 			: LLRefCount(),
-			  mRegionID(region_id)
+			  mRegionHandle(region_handle)
 			{
 				reset();
 			}
@@ -127,7 +134,7 @@ public:
 		void accumulateTime(duration_t now);
 		
 	public:
-		LLUUID mRegionID;
+		region_handle_t mRegionHandle;
 		duration_t mTotalTime;
 		duration_t mStartTimestamp;
 		
@@ -151,14 +158,14 @@ public:
 
 	// Set hidden region argument and establish context for subsequent
 	// collection calls.
-	void setRegionID(const LLUUID & region_id);
+	void setRegion(region_handle_t region_handle);
 
 	// Asset GET Requests
 	void recordGetEnqueued(LLViewerAssetType::EType at, bool with_http, bool is_temp);
 	void recordGetDequeued(LLViewerAssetType::EType at, bool with_http, bool is_temp);
 	void recordGetServiced(LLViewerAssetType::EType at, bool with_http, bool is_temp, duration_t duration);
 
-	// Retrieve current metrics for all visited regions (NULL region UUID excluded)
+	// Retrieve current metrics for all visited regions (NULL region UUID/handle excluded)
     // Returned LLSD is structured as follows:
 	//
 	// &stats_group = {
@@ -173,7 +180,7 @@ public:
 	// {
 	//   duration: int
 	//   regions: {
-	//     $: {
+	//     $: {			// Keys are strings of the region's handle in hex
 	//       duration:                 : int,
 	//       get_texture_temp_http     : &stats_group,
 	//       get_texture_temp_udp      : &stats_group,
@@ -198,12 +205,12 @@ public:
 	static void mergeRegionsLLSD(const LLSD & src, LLSD & dst);
 
 protected:
-	typedef std::map<LLUUID, LLPointer<PerRegionStats> > PerRegionContainer;
+	typedef std::map<region_handle_t, LLPointer<PerRegionStats> > PerRegionContainer;
 
 	// Region of the currently-active region.  Always valid but may
-	// be a NULL UUID after construction or when explicitly set.  Unchanged
+	// be zero after construction or when explicitly set.  Unchanged
 	// by a reset() call.
-	LLUUID mRegionID;
+	region_handle_t mRegionHandle;
 
 	// Pointer to metrics collection for currently-active region.  Always
 	// valid and unchanged after reset() though contents will be changed.
@@ -262,7 +269,7 @@ inline LLViewerAssetStats::duration_t get_timestamp()
 /**
  * Region context, event and duration loggers for the Main thread.
  */
-void set_region_main(const LLUUID & region_id);
+void set_region_main(LLViewerAssetStats::region_handle_t region_handle);
 
 void record_enqueue_main(LLViewerAssetType::EType at, bool with_http, bool is_temp);
 
@@ -275,7 +282,7 @@ void record_response_main(LLViewerAssetType::EType at, bool with_http, bool is_t
 /**
  * Region context, event and duration loggers for Thread 1.
  */
-void set_region_thread1(const LLUUID & region_id);
+void set_region_thread1(LLViewerAssetStats::region_handle_t region_handle);
 
 void record_enqueue_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp);
 
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 717ef40465..79b45a459f 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -1341,14 +1341,6 @@ void LLViewerRegion::unpackRegionHandshake()
 	msg->nextBlock("RegionInfo");
 	msg->addU32("Flags", 0x0 );
 	msg->sendReliable(host);
-
-	// Inform metrics when a region associated with an agent
-	// receives a regionID.
-	if (gAgent.getRegion() == this)
-	{
-		// Region is active in agent, tell metrics about the region ID
-		LLAppViewer::metricsUpdateRegion(region_id);
-	}
 }
 
 void LLViewerRegion::setSeedCapability(const std::string& url)
diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp
index 8bedd2c860..153056b3cd 100644
--- a/indra/newview/tests/llviewerassetstats_test.cpp
+++ b/indra/newview/tests/llviewerassetstats_test.cpp
@@ -78,6 +78,10 @@ static const char * sub_keys[] =
 
 static const LLUUID region1("4e2d81a3-6263-6ffe-ad5c-8ce04bee07e8");
 static const LLUUID region2("68762cc8-b68b-4e45-854b-e830734f2d4a");
+static const U64 region1_handle(0x00000401000003f7ULL);
+static const U64 region2_handle(0x000003f800000420ULL);
+static const std::string region1_handle_str("00000401000003f7");
+static const std::string region2_handle_str("000003f800000420");
 
 #if 0
 static bool
@@ -144,12 +148,12 @@ namespace tut
 		ensure("Stat-less LLSD initially", is_no_stats_map(sd_full));
 
 		// Once the region is set, we will get a response even with no data collection
-		it->setRegionID(region1);
+		it->setRegion(region1_handle);
 		sd_full = it->asLLSD();
 		ensure("Correct single-key LLSD map root", is_double_key_map(sd_full, "duration", "regions"));
-		ensure("Correct single-key LLSD map regions", is_single_key_map(sd_full["regions"], region1.asString()));
+		ensure("Correct single-key LLSD map regions", is_single_key_map(sd_full["regions"], region1_handle_str));
 		
-		LLSD sd = sd_full["regions"][region1.asString()];
+		LLSD sd = sd_full["regions"][region1_handle_str];
 
 		delete it;
 			
@@ -175,12 +179,12 @@ namespace tut
 	void tst_viewerassetstats_index_object_t::test<3>()
 	{
 		LLViewerAssetStats * it = new LLViewerAssetStats();
-		it->setRegionID(region1);
+		it->setRegion(region1_handle);
 		
 		LLSD sd = it->asLLSD();
 		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
-		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1.asString()));
-		sd = sd[region1.asString()];
+		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1_handle_str));
+		sd = sd[region1_handle_str];
 		
 		delete it;
 
@@ -194,7 +198,7 @@ namespace tut
 	void tst_viewerassetstats_index_object_t::test<4>()
 	{
 		gViewerAssetStatsMain = new LLViewerAssetStats();
-		LLViewerAssetStatsFF::set_region_main(region1);
+		LLViewerAssetStatsFF::set_region_main(region1_handle);
 
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false);
 		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false);
@@ -204,8 +208,8 @@ namespace tut
 
 		LLSD sd = gViewerAssetStatsMain->asLLSD();
 		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
-		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1.asString()));
-		sd = sd["regions"][region1.asString()];
+		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1_handle_str));
+		sd = sd["regions"][region1_handle_str];
 		
 		// Check a few points on the tree for content
 		ensure("sd[get_texture_non_temp_udp][enqueued] is 1", (1 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger()));
@@ -217,7 +221,7 @@ namespace tut
 		// Reset and check zeros...
 		// Reset leaves current region in place
 		gViewerAssetStatsMain->reset();
-		sd = gViewerAssetStatsMain->asLLSD()["regions"][region1.asString()];
+		sd = gViewerAssetStatsMain->asLLSD()["regions"][region1_handle_str];
 		
 		delete gViewerAssetStatsMain;
 		gViewerAssetStatsMain = NULL;
@@ -232,7 +236,7 @@ namespace tut
 	{
 		gViewerAssetStatsThread1 = new LLViewerAssetStats();
 		gViewerAssetStatsMain = new LLViewerAssetStats();
-		LLViewerAssetStatsFF::set_region_main(region1);
+		LLViewerAssetStatsFF::set_region_main(region1_handle);
 
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false);
 		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false);
@@ -244,8 +248,8 @@ namespace tut
 		ensure("Other collector is empty", is_no_stats_map(sd));
 		sd = gViewerAssetStatsMain->asLLSD();
 		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
-		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1.asString()));
-		sd = sd["regions"][region1.asString()];
+		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1_handle_str));
+		sd = sd["regions"][region1_handle_str];
 		
 		// Check a few points on the tree for content
 		ensure("sd[get_texture_non_temp_udp][enqueued] is 1", (1 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger()));
@@ -257,7 +261,7 @@ namespace tut
 		// Reset and check zeros...
 		// Reset leaves current region in place
 		gViewerAssetStatsMain->reset();
-		sd = gViewerAssetStatsMain->asLLSD()["regions"][region1.asString()];
+		sd = gViewerAssetStatsMain->asLLSD()["regions"][region1_handle_str];
 		
 		delete gViewerAssetStatsMain;
 		gViewerAssetStatsMain = NULL;
@@ -274,7 +278,7 @@ namespace tut
 	{
 		gViewerAssetStatsMain = new LLViewerAssetStats();
 
-		LLViewerAssetStatsFF::set_region_main(region1);
+		LLViewerAssetStatsFF::set_region_main(region1_handle);
 
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false);
 		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false);
@@ -282,7 +286,7 @@ namespace tut
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false);
 		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false);
 
-		LLViewerAssetStatsFF::set_region_main(region2);
+		LLViewerAssetStatsFF::set_region_main(region2_handle);
 
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
@@ -294,9 +298,9 @@ namespace tut
 		// std::cout << sd << std::endl;
 		
 		ensure("Correct double-key LLSD map root", is_double_key_map(sd, "duration", "regions"));
-		ensure("Correct double-key LLSD map regions", is_double_key_map(sd["regions"], region1.asString(), region2.asString()));
-		LLSD sd1 = sd["regions"][region1.asString()];
-		LLSD sd2 = sd["regions"][region2.asString()];
+		ensure("Correct double-key LLSD map regions", is_double_key_map(sd["regions"], region1_handle_str, region2_handle_str));
+		LLSD sd1 = sd["regions"][region1_handle_str];
+		LLSD sd2 = sd["regions"][region2_handle_str];
 		
 		// Check a few points on the tree for content
 		ensure("sd1[get_texture_non_temp_udp][enqueued] is 1", (1 == sd1["get_texture_non_temp_udp"]["enqueued"].asInteger()));
@@ -315,8 +319,8 @@ namespace tut
 		gViewerAssetStatsMain->reset();
 		sd = gViewerAssetStatsMain->asLLSD();
 		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
-		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region2.asString()));
-		sd2 = sd["regions"][region2.asString()];
+		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region2_handle_str));
+		sd2 = sd["regions"][region2_handle_str];
 		
 		delete gViewerAssetStatsMain;
 		gViewerAssetStatsMain = NULL;
@@ -331,7 +335,7 @@ namespace tut
 	{
 		gViewerAssetStatsMain = new LLViewerAssetStats();
 
-		LLViewerAssetStatsFF::set_region_main(region1);
+		LLViewerAssetStatsFF::set_region_main(region1_handle);
 
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false);
 		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false);
@@ -339,14 +343,14 @@ namespace tut
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false);
 		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false);
 
-		LLViewerAssetStatsFF::set_region_main(region2);
+		LLViewerAssetStatsFF::set_region_main(region2_handle);
 
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
 
-		LLViewerAssetStatsFF::set_region_main(region1);
+		LLViewerAssetStatsFF::set_region_main(region1_handle);
 
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, true, true);
 		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, true, true);
@@ -354,7 +358,7 @@ namespace tut
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false);
 		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false);
 
-		LLViewerAssetStatsFF::set_region_main(region2);
+		LLViewerAssetStatsFF::set_region_main(region2_handle);
 
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
@@ -364,9 +368,9 @@ namespace tut
 		LLSD sd = gViewerAssetStatsMain->asLLSD();
 
 		ensure("Correct double-key LLSD map root", is_double_key_map(sd, "duration", "regions"));
-		ensure("Correct double-key LLSD map regions", is_double_key_map(sd["regions"], region1.asString(), region2.asString()));
-		LLSD sd1 = sd["regions"][region1.asString()];
-		LLSD sd2 = sd["regions"][region2.asString()];
+		ensure("Correct double-key LLSD map regions", is_double_key_map(sd["regions"], region1_handle_str, region2_handle_str));
+		LLSD sd1 = sd["regions"][region1_handle_str];
+		LLSD sd2 = sd["regions"][region2_handle_str];
 		
 		// Check a few points on the tree for content
 		ensure("sd1[get_texture_non_temp_udp][enqueued] is 1", (1 == sd1["get_texture_non_temp_udp"]["enqueued"].asInteger()));
@@ -385,8 +389,8 @@ namespace tut
 		gViewerAssetStatsMain->reset();
 		sd = gViewerAssetStatsMain->asLLSD();
 		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "duration", "regions"));
-		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region2.asString()));
-		sd2 = sd["regions"][region2.asString()];
+		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region2_handle_str));
+		sd2 = sd["regions"][region2_handle_str];
 		
 		delete gViewerAssetStatsMain;
 		gViewerAssetStatsMain = NULL;
@@ -401,7 +405,7 @@ namespace tut
 	{
 		gViewerAssetStatsThread1 = new LLViewerAssetStats();
 		gViewerAssetStatsMain = new LLViewerAssetStats();
-		LLViewerAssetStatsFF::set_region_main(region1);
+		LLViewerAssetStatsFF::set_region_main(region1_handle);
 
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_TEXTURE, false, false);
 		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_TEXTURE, false, false);
@@ -430,8 +434,8 @@ namespace tut
 		ensure("Other collector is empty", is_no_stats_map(sd));
 		sd = gViewerAssetStatsMain->asLLSD();
 		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
-		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1.asString()));
-		sd = sd["regions"][region1.asString()];
+		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1_handle_str));
+		sd = sd["regions"][region1_handle_str];
 		
 		// Check a few points on the tree for content
 		ensure("sd[get_gesture_udp][enqueued] is 0", (0 == sd["get_gesture_udp"]["enqueued"].asInteger()));
@@ -446,7 +450,7 @@ namespace tut
 		// Reset and check zeros...
 		// Reset leaves current region in place
 		gViewerAssetStatsMain->reset();
-		sd = gViewerAssetStatsMain->asLLSD()["regions"][region1.asString()];
+		sd = gViewerAssetStatsMain->asLLSD()["regions"][region1_handle_str];
 		
 		delete gViewerAssetStatsMain;
 		gViewerAssetStatsMain = NULL;
@@ -461,8 +465,8 @@ namespace tut
 	template<> template<>
 	void tst_viewerassetstats_index_object_t::test<9>()
 	{
-		LLSD::String reg1_name = region1.asString();
-		LLSD::String reg2_name = region2.asString();
+		LLSD::String reg1_name = region1_handle_str;
+		LLSD::String reg2_name = region2_handle_str;
 
 		LLSD reg1_stats = LLSD::emptyMap();
 		LLSD reg2_stats = LLSD::emptyMap();
@@ -523,8 +527,8 @@ namespace tut
 	template<> template<>
 	void tst_viewerassetstats_index_object_t::test<10>()
 	{
-		LLSD::String reg1_name = region1.asString();
-		LLSD::String reg2_name = region2.asString();
+		LLSD::String reg1_name = region1_handle_str;
+		LLSD::String reg2_name = region2_handle_str;
 
 		LLSD reg1_stats = LLSD::emptyMap();
 		LLSD reg2_stats = LLSD::emptyMap();
@@ -580,8 +584,8 @@ namespace tut
 	template<> template<>
 	void tst_viewerassetstats_index_object_t::test<11>()
 	{
-		LLSD::String reg1_name = region1.asString();
-		LLSD::String reg2_name = region2.asString();
+		LLSD::String reg1_name = region1_handle_str;
+		LLSD::String reg2_name = region2_handle_str;
 
 		LLSD reg1_stats = LLSD::emptyMap();
 		LLSD reg2_stats = LLSD::emptyMap();
@@ -637,8 +641,8 @@ namespace tut
 	template<> template<>
 	void tst_viewerassetstats_index_object_t::test<12>()
 	{
-		LLSD::String reg1_name = region1.asString();
-		LLSD::String reg2_name = region2.asString();
+		LLSD::String reg1_name = region1_handle_str;
+		LLSD::String reg2_name = region2_handle_str;
 
 		LLSD reg1_stats = LLSD::emptyMap();
 		LLSD reg2_stats = LLSD::emptyMap();
-- 
cgit v1.2.3


From 922b1f26b7279b5f54562c413c333463fe34473b Mon Sep 17 00:00:00 2001
From: Monty Brandenberg <monty@lindenlab.com>
Date: Thu, 2 Dec 2010 18:42:47 -0500
Subject: ESC-211 Metrics data sink - fix delivery by viewer The TextureFetch
 thread was still stalling out due to a different path that determines whether
 there is work or not in the thread (uses getPending()) and that had to be
 harmonized with the changes to runCondition(). I'm not happy with this
 solution but a refactor of the LLThread tree isn't in the cards right now.

---
 indra/newview/lltexturefetch.cpp | 89 +++++++++++++++++++++++++++++++++++-----
 indra/newview/lltexturefetch.h   |  1 +
 2 files changed, 79 insertions(+), 11 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index 3793085e55..dd84290e90 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -568,6 +568,14 @@ public:
 	LLSD * mReportMain;
 };
 
+/*
+ * Count of POST requests outstanding.  We maintain the count
+ * indirectly in the CURL request responder's ctor and dtor and
+ * use it when determining whether or not to sleep the flag.  Can't
+ * use the LLCurl module's request counter as it isn't thread compatible.
+ */
+LLAtomic32<S32> curl_post_request_count = 0;
+    
 } // end of anonymous namespace
 
 
@@ -2084,6 +2092,33 @@ bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority)
 	return res;
 }
 
+// Replicates and expands upon the base class's
+// getPending() implementation.  getPending() and
+// runCondition() replicate one another's logic to
+// an extent and are sometimes used for the same
+// function (deciding whether or not to sleep/pause
+// a thread).  So the implementations need to stay
+// in step, at least until this can be refactored and
+// the redundancy eliminated.
+//
+// May be called from any thread
+
+//virtual
+S32 LLTextureFetch::getPending()
+{
+	S32 res;
+	lockData();
+    {
+        LLMutexLock lock(&mQueueMutex);
+        
+        res = mRequestQueue.size();
+        res += curl_post_request_count;
+        res += mCommands.size();
+    }
+	unlockData();
+	return res;
+}
+
 // virtual
 bool LLTextureFetch::runCondition()
 {
@@ -2100,7 +2135,12 @@ bool LLTextureFetch::runCondition()
 		
 		have_no_commands = mCommands.empty();
 	}
-	return ! (have_no_commands && mRequestQueue.empty() && mIdleThread);
+	
+    bool have_no_curl_requests(0 == curl_post_request_count);
+	
+	return ! (have_no_commands
+             && have_no_curl_requests
+             && (mRequestQueue.empty() && mIdleThread));
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -2116,7 +2156,7 @@ void LLTextureFetch::commonUpdate()
 	if (processed > 0)
 	{
 		lldebugs << "processed: " << processed << " messages." << llendl;
-	}	
+	}
 }
 
 
@@ -2766,31 +2806,56 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
 	 * the referenced data is part of a pseudo-closure for
 	 * this responder rather than being required for correct
 	 * operation.
+     *
+     * We don't try very hard with the POST request.  We give
+     * it one shot and that's more-or-less it.  With a proper
+     * refactoring of the LLQueuedThread usage, these POSTs
+     * could be put in a request object and made more reliable.
 	 */
 	class lcl_responder : public LLCurl::Responder
 	{
 	public:
-		lcl_responder(volatile bool & reporting_break,
+		lcl_responder(S32 expected_sequence,
+                      volatile const S32 & live_sequence,
+                      volatile bool & reporting_break,
 					  volatile bool & reporting_started)
-			: LLHTTPClient::Responder(),
+			: LLCurl::Responder(),
+              mExpectedSequence(expected_sequence),
+              mLiveSequence(live_sequence),
 			  mReportingBreak(reporting_break),
 			  mReportingStarted(reporting_started)
-			{}
+			{
+                curl_post_request_count++;
+            }
+        
+        ~lcl_responder()
+            {
+                curl_post_request_count--;
+            }
 
 		// virtual
 		void error(U32 status_num, const std::string & reason)
 			{
-				mReportingBreak = true;
+                if (mLiveSequence == mExpectedSequence)
+                {
+                    mReportingBreak = true;
+                }
 			}
 
 		// virtual
 		void result(const LLSD & content)
 			{
-				mReportingBreak = false;
-				mReportingStarted = true;
+                if (mLiveSequence == mExpectedSequence)
+                {
+                    mReportingBreak = false;
+                    mReportingStarted = true;
+                }
 			}
+        
 
 	private:
+        S32 mExpectedSequence;
+        volatile const S32 & mLiveSequence;
 		volatile bool & mReportingBreak;
 		volatile bool & mReportingStarted;
 	};
@@ -2799,8 +2864,8 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
 		return true;
 
 	static volatile bool reporting_started(false);
-	static S32 report_sequence(0);
-
+	static volatile S32 report_sequence(0);
+    
 	// We've already taken over ownership of the LLSD at this point
 	// and can do normal LLSD sharing operations at this point.  But
 	// still being careful, regardless.
@@ -2826,7 +2891,9 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
 		fetcher->getCurlRequest().post(mCapsURL,
 									   headers,
 									   thread1_stats,
-									   new lcl_responder(LLTextureFetch::svMetricsDataBreak,
+									   new lcl_responder(report_sequence,
+                                                         report_sequence,
+                                                         LLTextureFetch::svMetricsDataBreak,
 														 reporting_started));
 	}
 	else
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index 03e2462058..af30d1bb3b 100644
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -78,6 +78,7 @@ public:
 	S32 getNumHTTPRequests() ;
 	
 	// Public for access by callbacks
+    S32 getPending();
 	void lockQueue() { mQueueMutex.lock(); }
 	void unlockQueue() { mQueueMutex.unlock(); }
 	LLTextureFetchWorker* getWorker(const LLUUID& id);
-- 
cgit v1.2.3


From ca76c55847cdaabe662c880c4d744916c8ca71ac Mon Sep 17 00:00:00 2001
From: Monty Brandenberg <monty@lindenlab.com>
Date: Fri, 3 Dec 2010 12:31:12 -0800
Subject: ESC-211 ESC-222 Viewer/Sim comms and outbound data throttle Cleaned
 up some of the messaging code that sends the LLSD stats report off to the
 viewer.  Added WARNS-level messages when there's a problem with delivery that
 will result in a data break.  Users probably won't care.  Added an outbound
 data throttle that limits stats to the 10 regions of longest occupancy. 
 Should be a reasonable first cut.

---
 indra/newview/lltexturefetch.cpp | 75 ++++++++++++++++++++++++++++++++++------
 1 file changed, 65 insertions(+), 10 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index dd84290e90..b46f338303 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -27,6 +27,7 @@
 #include "llviewerprecompiledheaders.h"
 
 #include <iostream>
+#include <map>
 
 #include "llstl.h"
 
@@ -446,7 +447,7 @@ namespace
  *                        .                   +-----+
  *                        .                      |
  *                        .                   +-----+
- *                        .                   | CP  |--> HTTP PUT
+ *                        .                   | CP  |--> HTTP POST
  *                        .                   +-----+
  *                        .                      .
  *                        .                      .
@@ -469,7 +470,7 @@ namespace
  *       new region.
  * TE  - Timer Expired.  Metrics timer has expired (on the order
  *       of 10 minutes).
- * CP  - CURL Put
+ * CP  - CURL Post
  * MSC - Modify Stats Collector.  State change in the thread-local
  *       collector.  Typically a region change which affects the
  *       global pointers used to find the 'current stats'.
@@ -571,11 +572,23 @@ public:
 /*
  * Count of POST requests outstanding.  We maintain the count
  * indirectly in the CURL request responder's ctor and dtor and
- * use it when determining whether or not to sleep the flag.  Can't
+ * use it when determining whether or not to sleep the thread.  Can't
  * use the LLCurl module's request counter as it isn't thread compatible.
  */
 LLAtomic32<S32> curl_post_request_count = 0;
-    
+
+/*
+ * Examines the merged viewer metrics report and if found to be too long,
+ * will attempt to truncate it in some reasonable fashion.
+ *
+ * @param		max_regions		Limit of regions allowed in report.
+ *
+ * @param		metrics			Full, merged viewer metrics report.
+ *
+ * @returns		If data was truncated, returns true.
+ */
+bool truncate_viewer_metrics(int max_regions, LLSD & metrics);
+
 } // end of anonymous namespace
 
 
@@ -2128,7 +2141,9 @@ bool LLTextureFetch::runCondition()
 	// private method which is unfortunate.  I want to use it directly
 	// but I'm going to have to re-implement the logic here (or change
 	// declarations, which I don't want to do right now).
-
+	//
+	// Changes here may need to be reflected in getPending().
+	
 	bool have_no_commands(false);
 	{
 		LLMutexLock lock(&mQueueMutex);
@@ -2139,8 +2154,8 @@ bool LLTextureFetch::runCondition()
     bool have_no_curl_requests(0 == curl_post_request_count);
 	
 	return ! (have_no_commands
-             && have_no_curl_requests
-             && (mRequestQueue.empty() && mIdleThread));
+			  && have_no_curl_requests
+			  && (mRequestQueue.empty() && mIdleThread));		// From base class
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -2840,6 +2855,8 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
                 {
                     mReportingBreak = true;
                 }
+				LL_WARNS("Texture") << "Break in metrics stream due to POST failure to metrics collection service.  Reason:  "
+									<< reason << LL_ENDL;
 			}
 
 		// virtual
@@ -2851,14 +2868,14 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
                     mReportingStarted = true;
                 }
 			}
-        
 
 	private:
         S32 mExpectedSequence;
         volatile const S32 & mLiveSequence;
 		volatile bool & mReportingBreak;
 		volatile bool & mReportingStarted;
-	};
+
+	}; // class lcl_responder
 	
 	if (! gViewerAssetStatsThread1)
 		return true;
@@ -2884,7 +2901,9 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
 	// Merge the two LLSDs into a single report
 	LLViewerAssetStatsFF::merge_stats(main_stats, thread1_stats);
 
-	// *TODO:  Consider putting a report size limiter here.
+	// Limit the size of the stats report if necessary.
+	thread1_stats["truncated"] = truncate_viewer_metrics(10, thread1_stats);
+
 	if (! mCapsURL.empty())
 	{
 		LLCurlRequest::headers_t headers;
@@ -2912,6 +2931,42 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
 	return true;
 }
 
+
+bool
+truncate_viewer_metrics(int max_regions, LLSD & metrics)
+{
+	static const LLSD::String reg_tag("regions");
+	static const LLSD::String duration_tag("duration");
+	
+	LLSD & reg_map(metrics[reg_tag]);
+	if (reg_map.size() <= max_regions)
+	{
+		return false;
+	}
+
+	// Build map of region hashes ordered by duration
+	typedef std::multimap<LLSD::Integer, LLSD::String> reg_ordered_list_t;
+	reg_ordered_list_t regions_by_duration;
+
+	LLSD::map_const_iterator it_end(reg_map.endMap());
+	for (LLSD::map_const_iterator it(reg_map.beginMap()); it_end != it; ++it)
+	{
+		LLSD::Integer duration = (it->second)[duration_tag].asInteger();
+		regions_by_duration.insert(reg_ordered_list_t::value_type(duration, it->first));
+	}
+
+	// Erase excess region reports selecting shortest duration first
+	reg_ordered_list_t::const_iterator it2_end(regions_by_duration.end());
+	reg_ordered_list_t::const_iterator it2(regions_by_duration.begin());
+	int limit(regions_by_duration.size() - max_regions);
+	for (int i(0); i < limit && it2_end != it2; ++i, ++it2)
+	{
+		reg_map.erase(it2->second);
+	}
+
+	return true;
+}
+
 } // end of anonymous namespace
 
 
-- 
cgit v1.2.3


From a59c43f1adff35107e59fdfc3016d4329324bbaf Mon Sep 17 00:00:00 2001
From: Monty Brandenberg <monty@lindenlab.com>
Date: Fri, 3 Dec 2010 18:34:20 -0500
Subject: ESC-210  Non-active regions were getting extra duration time. Metrics
 were crediting inactive regions (those not current but contributing to the
 sample) with additional time at the end of the sample interval.  Corrected.

---
 indra/newview/llviewerassetstats.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp
index cc41a95893..d798786277 100644
--- a/indra/newview/llviewerassetstats.cpp
+++ b/indra/newview/llviewerassetstats.cpp
@@ -240,8 +240,9 @@ LLViewerAssetStats::asLLSD()
 	static const LLSD::String rmean_tag("resp_mean");
 
 	const duration_t now = LLViewerAssetStatsFF::get_timestamp();
-	LLSD regions = LLSD::emptyMap();
+	mCurRegionStats->accumulateTime(now);
 
+	LLSD regions = LLSD::emptyMap();
 	for (PerRegionContainer::iterator it = mRegionStats.begin();
 		 mRegionStats.end() != it;
 		 ++it)
@@ -253,7 +254,6 @@ LLViewerAssetStats::asLLSD()
 		}
 
 		PerRegionStats & stats = *it->second;
-		stats.accumulateTime(now);
 		
 		LLSD reg_stat = LLSD::emptyMap();
 		
-- 
cgit v1.2.3


From c28b476a6806a426593e6798ea537f13ca354fc8 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Wed, 8 Dec 2010 15:26:36 -0800
Subject: EXP-448 FIX Notification not found error for NofileExtension given
 when uploading file with no file extension during Bulk Upload

---
 indra/newview/llviewermenufile.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index 048691696b..b7be3bc5b3 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -505,7 +505,7 @@ void upload_new_resource(const std::string& src_filename, std::string name,
 				"No file extension for the file: '%s'\nPlease make sure the file has a correct file extension",
 				short_name.c_str());
 		args["FILE"] = short_name;
- 		upload_error(error_message, "NofileExtension", filename, args);
+ 		upload_error(error_message, "NoFileExtension", filename, args);
 		return;
 	}
 	else if( exten == "bmp")
-- 
cgit v1.2.3


From e7cd5f7e614e9884398d505a47376188c693d685 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Wed, 8 Dec 2010 16:40:56 -0800
Subject: EXP-445 FIXED Skylight view hint shown in main viewer skin and not
 dismissed when using orbit pan zoom tools.

---
 indra/newview/skins/default/xui/en/notification_visibility.xml | 1 +
 1 file changed, 1 insertion(+)

(limited to 'indra/newview')

diff --git a/indra/newview/skins/default/xui/en/notification_visibility.xml b/indra/newview/skins/default/xui/en/notification_visibility.xml
index d32066a5a5..e1973f926f 100644
--- a/indra/newview/skins/default/xui/en/notification_visibility.xml
+++ b/indra/newview/skins/default/xui/en/notification_visibility.xml
@@ -1,6 +1,7 @@
 <?xml version="1.0" ?>
 <notification_visibility>
   <hide name="HintMoveArrows"/>
+  <hide name="HintView"/>
 	<show/> 
 </notification_visibility>
 
-- 
cgit v1.2.3


From e17eea11a8befd5c09a0975a1b7b7ec6bb667368 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Wed, 8 Dec 2010 16:53:37 -0800
Subject: EXP-445 FIXED Skylight view hint shown in main viewer skin and not
 dismissed when using orbit pan zoom tools. better fix that uses tag to
 isolate all skin specific notifications

---
 indra/newview/skins/default/xui/en/notification_visibility.xml | 3 +--
 indra/newview/skins/default/xui/en/notifications.xml           | 4 +++-
 2 files changed, 4 insertions(+), 3 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/skins/default/xui/en/notification_visibility.xml b/indra/newview/skins/default/xui/en/notification_visibility.xml
index e1973f926f..db292100d7 100644
--- a/indra/newview/skins/default/xui/en/notification_visibility.xml
+++ b/indra/newview/skins/default/xui/en/notification_visibility.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" ?>
 <notification_visibility>
-  <hide name="HintMoveArrows"/>
-  <hide name="HintView"/>
+  <hide tag="custom_skin"/>
 	<show/> 
 </notification_visibility>
 
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index c1fad9050b..b1fd579c6f 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -6583,14 +6583,16 @@ Mute everyone?
   type="hint"
   unique="true">
     To walk, use the directional keys on your keyboard. You can run by pressing the Up arrow twice.
+    <tag>custom_skin</tag>
   </notification>
-  
+
   <notification
   name="HintView"
   label="View"
   type="hint"
   unique="true">
     To change your camera view, use the Orbit and Pan controls. Reset your view by pressing Escape or walking.
+    <tag>custom_skin</tag>
   </notification>
 
   <notification
-- 
cgit v1.2.3


From cf6147f7c092e6ca10697dea341099c5e281df00 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Wed, 8 Dec 2010 17:28:27 -0800
Subject: EXP-465 FIX Viewer window does not fill screen on Mac and Linux using
 --fullscreen disabled fullscreen mode for merge to viewer-development

---
 indra/newview/app_settings/cmd_line.xml | 7 -------
 indra/newview/llappviewer.cpp           | 3 +++
 2 files changed, 3 insertions(+), 7 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/app_settings/cmd_line.xml b/indra/newview/app_settings/cmd_line.xml
index 294d85eac1..e4ac455e7c 100644
--- a/indra/newview/app_settings/cmd_line.xml
+++ b/indra/newview/app_settings/cmd_line.xml
@@ -392,13 +392,6 @@
       <string>CrashOnStartup</string>
     </map>
 
-    <key>fullscreen</key>
-    <map>
-      <key>desc</key>
-      <string>Force full screen mode</string>
-      <key>map-to</key>
-      <string>WindowFullScreen</string>
-    </map>
     <key>disablecrashlogger</key>
     <map>
       <key>desc</key>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index cd53fb8970..b460885a53 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -505,6 +505,9 @@ static void settings_modify()
 	gSavedSettings.setBOOL("VectorizeEnable", FALSE );
 	gSavedSettings.setU32("VectorizeProcessor", 0 );
 	gSavedSettings.setBOOL("VectorizeSkin", FALSE);
+
+	// disable fullscreen mode, unsupported
+	gSavedSettings.setBOOL("WindowFullScreen", FALSE);
 #endif
 }
 
-- 
cgit v1.2.3


From ee538257d316696382d12ea222294a4b8786dc84 Mon Sep 17 00:00:00 2001
From: Paul Guslisty <pguslisty@productengine.com>
Date: Fri, 10 Dec 2010 13:01:01 +0200
Subject: STORM-622 FIXED Texture picker screws up when multiple textures are
 opened.

Reason:
	In viewer 2 ability was added to set aspect ratio while previewing textures. It was achieved by resizing the floater containing a texture, instead of proportionally resize the texture. The problem happened when multifloater was opened with texture preview floaters and for some floaters textures were not loaded yet. After texture was loaded, the floater (in multifloater) which contained just loaded texture resized to fit with the new texture's size and texture preview floaters screwed up from the multifloater.

Solution:
        Proportionally resizing a texture inside the floater instead of the floater itself.

Also two issues was fixed: 1. when floater resized the texture streched in the floater and lost its proportions. 2. When docking texture floater to the multifloater, multifloater resized to fit with docked floater and other texture lost their proportions.
---
 indra/newview/llpreview.cpp        |  3 +-
 indra/newview/llpreviewtexture.cpp | 77 ++------------------------------------
 2 files changed, 6 insertions(+), 74 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llpreview.cpp b/indra/newview/llpreview.cpp
index 69542764d2..a90f23d637 100644
--- a/indra/newview/llpreview.cpp
+++ b/indra/newview/llpreview.cpp
@@ -454,12 +454,13 @@ LLMultiPreview::LLMultiPreview()
 	{
 		// start with a rect in the top-left corner ; will get resized
 		LLRect rect;
-		rect.setLeftTopAndSize(0, gViewerWindow->getWindowHeightScaled(), 200, 200);
+		rect.setLeftTopAndSize(0, gViewerWindow->getWindowHeightScaled(), 200, 400);
 		setRect(rect);
 	}
 	setTitle(LLTrans::getString("MultiPreviewTitle"));
 	buildTabContainer();
 	setCanResize(TRUE);
+	mAutoResize = FALSE;
 }
 
 void LLMultiPreview::onOpen(const LLSD& key)
diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp
index fd6b326ef1..7657cccd4e 100644
--- a/indra/newview/llpreviewtexture.cpp
+++ b/indra/newview/llpreviewtexture.cpp
@@ -318,7 +318,7 @@ void LLPreviewTexture::reshape(S32 width, S32 height, BOOL called_from_parent)
 		}
 	}
 
-	mClientRect.setLeftTopAndSize(client_rect.getCenterX() - (client_width / 2), client_rect.getCenterY() +  (client_height / 2), client_width, client_height);	
+	mClientRect.setLeftTopAndSize(client_rect.getCenterX() - (client_width / 2), client_rect.getCenterY() +  (client_height / 2), client_width, client_height);
 
 }
 
@@ -400,7 +400,6 @@ void LLPreviewTexture::updateDimensions()
 	{
 		return;
 	}
-
 	
 	mUpdateDimensions = FALSE;
 
@@ -408,80 +407,12 @@ void LLPreviewTexture::updateDimensions()
 	getChild<LLUICtrl>("dimensions")->setTextArg("[HEIGHT]", llformat("%d", mImage->getFullHeight()));
 
 	
-	LLRect dim_rect(getChildView("dimensions")->getRect());
-
-	S32 horiz_pad = 2 * (LLPANEL_BORDER_WIDTH + PREVIEW_PAD) + PREVIEW_RESIZE_HANDLE_SIZE;
-
-	// add space for dimensions and aspect ratio
-	S32 info_height = dim_rect.mTop + CLIENT_RECT_VPAD;
-
-	S32 screen_width = gFloaterView->getSnapRect().getWidth();
-	S32 screen_height = gFloaterView->getSnapRect().getHeight();
-
-	S32 max_image_width = screen_width - 2*horiz_pad;
-	S32 max_image_height = screen_height - (PREVIEW_HEADER_SIZE + CLIENT_RECT_VPAD) 
-		- (PREVIEW_BORDER + CLIENT_RECT_VPAD + info_height);
-
-	S32 client_width = llmin(max_image_width,mImage->getFullWidth());
-	S32 client_height = llmin(max_image_height,mImage->getFullHeight());
-
-	if (mAspectRatio > 0.f)
-	{
-		if(mAspectRatio > 1.f)
-		{
-			client_height = llceil((F32)client_width / mAspectRatio);
-			if(client_height > max_image_height)
-			{
-				client_height = max_image_height;
-				client_width = llceil((F32)client_height * mAspectRatio);
-			}
-		}
-		else//mAspectRatio < 1.f
-		{
-			client_width = llceil((F32)client_height * mAspectRatio);
-			if(client_width > max_image_width)
-			{
-				client_width = max_image_width;
-				client_height = llceil((F32)client_width / mAspectRatio);
-			}
-		}
-	}
-	else
-	{
-
-		if(client_height > max_image_height)
-		{
-			F32 ratio = (F32)max_image_height/client_height;
-			client_height = max_image_height;
-			client_width = llceil((F32)client_height * ratio);
-		}
-		
-		if(client_width > max_image_width)
-		{
-			F32 ratio = (F32)max_image_width/client_width;
-			client_width = max_image_width;
-			client_height = llceil((F32)client_width * ratio);
-		}
-	}
-
-	//now back to whole floater
-	S32 floater_width = llmax(getMinWidth(),client_width + 2*horiz_pad);
-	S32 floater_height = llmax(getMinHeight(),client_height + (PREVIEW_HEADER_SIZE + CLIENT_RECT_VPAD)
-		+ (PREVIEW_BORDER + CLIENT_RECT_VPAD + info_height));
-
 	//reshape floater
-	reshape( floater_width, floater_height );
-	gFloaterView->adjustToFitScreen(this, FALSE);
+	reshape(getRect().getWidth(), getRect().getHeight());
 
-	//setup image rect...
-	LLRect client_rect(horiz_pad, getRect().getHeight(), getRect().getWidth() - horiz_pad, 0);
-	client_rect.mTop -= (PREVIEW_HEADER_SIZE + CLIENT_RECT_VPAD);
-	client_rect.mBottom += PREVIEW_BORDER + CLIENT_RECT_VPAD + info_height ;
-
-	mClientRect.setLeftTopAndSize(client_rect.getCenterX() - (client_width / 2), client_rect.getCenterY() +  (client_height / 2), client_width, client_height);	
+	gFloaterView->adjustToFitScreen(this, FALSE);
 
-	// Hide the aspect ratio label if the window is too narrow
-	// Assumes the label should be to the right of the dimensions
+	LLRect dim_rect(getChildView("dimensions")->getRect());
 	LLRect aspect_label_rect(getChildView("aspect_ratio")->getRect());
 	getChildView("aspect_ratio")->setVisible( dim_rect.mRight < aspect_label_rect.mLeft);
 }
-- 
cgit v1.2.3


From a42b6acd6ae677a4347771baa49d75dc560269a3 Mon Sep 17 00:00:00 2001
From: Vadim ProductEngine <vsavchuk@productengine.com>
Date: Fri, 10 Dec 2010 16:30:45 +0200
Subject: STORM-431 FIXED Hot keys did't work with autocompletion in search
 field.

---
 indra/newview/llsearchcombobox.cpp | 3 +++
 1 file changed, 3 insertions(+)

(limited to 'indra/newview')

diff --git a/indra/newview/llsearchcombobox.cpp b/indra/newview/llsearchcombobox.cpp
index db531b5695..6558c9a7fa 100644
--- a/indra/newview/llsearchcombobox.cpp
+++ b/indra/newview/llsearchcombobox.cpp
@@ -131,6 +131,9 @@ void LLSearchComboBox::focusTextEntry()
 	if (mTextEntry)
 	{
 		gFocusMgr.setKeyboardFocus(mTextEntry);
+
+		// Let the editor handle editing hotkeys (STORM-431).
+		LLEditMenuHandler::gEditMenuHandler = mTextEntry;
 	}
 }
 
-- 
cgit v1.2.3


From 18a18f5985c76adaed040b4bdcba15cc251dbeb5 Mon Sep 17 00:00:00 2001
From: Seth ProductEngine <slitovchuk@productengine.com>
Date: Fri, 10 Dec 2010 19:13:25 +0200
Subject: STORM-693 FIXED Preview thumbnails in the Edit Wearable and Edit Body
 Parts panels now follow opacity settings for inactive floater. When the
 floater is active the thumbnails are opaque. The behavior is similar to
 texture control's.

---
 indra/newview/llscrollingpanelparam.cpp | 8 ++++++--
 indra/newview/lltoolmorph.cpp           | 4 ++--
 indra/newview/lltoolmorph.h             | 2 +-
 3 files changed, 9 insertions(+), 5 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llscrollingpanelparam.cpp b/indra/newview/llscrollingpanelparam.cpp
index 05b273cd29..f8c20dada0 100644
--- a/indra/newview/llscrollingpanelparam.cpp
+++ b/indra/newview/llscrollingpanelparam.cpp
@@ -165,12 +165,16 @@ void LLScrollingPanelParam::draw()
 	getChildView("max param text")->setVisible( FALSE );
 	LLPanel::draw();
 
+	// If we're in a focused floater, don't apply the floater's alpha to visual param hint,
+	// making its behavior similar to texture controls'.
+	F32 alpha = getTransparencyType() == TT_ACTIVE ? 1.0f : getCurrentTransparency();
+
 	// Draw the hints over the "less" and "more" buttons.
 	gGL.pushUIMatrix();
 	{
 		const LLRect& r = mHintMin->getRect();
 		gGL.translateUI((F32)r.mLeft, (F32)r.mBottom, 0.f);
-		mHintMin->draw();
+		mHintMin->draw(alpha);
 	}
 	gGL.popUIMatrix();
 
@@ -178,7 +182,7 @@ void LLScrollingPanelParam::draw()
 	{
 		const LLRect& r = mHintMax->getRect();
 		gGL.translateUI((F32)r.mLeft, (F32)r.mBottom, 0.f);
-		mHintMax->draw();
+		mHintMax->draw(alpha);
 	}
 	gGL.popUIMatrix();
 
diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp
index ca80a1db79..964b17d3a6 100644
--- a/indra/newview/lltoolmorph.cpp
+++ b/indra/newview/lltoolmorph.cpp
@@ -244,13 +244,13 @@ BOOL LLVisualParamHint::render()
 //-----------------------------------------------------------------------------
 // draw()
 //-----------------------------------------------------------------------------
-void LLVisualParamHint::draw()
+void LLVisualParamHint::draw(F32 alpha)
 {
 	if (!mIsVisible) return;
 
 	gGL.getTexUnit(0)->bind(this);
 
-	gGL.color4f(1.f, 1.f, 1.f, 1.f);
+	gGL.color4f(1.f, 1.f, 1.f, alpha);
 
 	LLGLSUIDefault gls_ui;
 	gGL.begin(LLRender::QUADS);
diff --git a/indra/newview/lltoolmorph.h b/indra/newview/lltoolmorph.h
index 59201233ae..a6889be151 100644
--- a/indra/newview/lltoolmorph.h
+++ b/indra/newview/lltoolmorph.h
@@ -68,7 +68,7 @@ public:
 	BOOL					render();
 	void					requestUpdate( S32 delay_frames ) {mNeedsUpdate = TRUE; mDelayFrames = delay_frames; }
 	void					setUpdateDelayFrames( S32 delay_frames ) { mDelayFrames = delay_frames; }
-	void					draw();
+	void					draw(F32 alpha);
 	
 	LLViewerVisualParam*	getVisualParam() { return mVisualParam; }
 	F32						getVisualParamWeight() { return mVisualParamWeight; }
-- 
cgit v1.2.3


From 26d063f5521f80bc7eca214fb8338fee4e87f301 Mon Sep 17 00:00:00 2001
From: Seth ProductEngine <slitovchuk@productengine.com>
Date: Fri, 10 Dec 2010 19:54:07 +0200
Subject: STORM-378 FIX REVERTED Backed out changeset: 1bce3dd882df

---
 indra/newview/llfloaterpostcard.cpp | 4 +++-
 indra/newview/llfloatersnapshot.cpp | 7 +++++++
 indra/newview/llviewermenufile.cpp  | 2 ++
 3 files changed, 12 insertions(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llfloaterpostcard.cpp b/indra/newview/llfloaterpostcard.cpp
index 054ab4538b..dd0b1d999c 100644
--- a/indra/newview/llfloaterpostcard.cpp
+++ b/indra/newview/llfloaterpostcard.cpp
@@ -366,7 +366,9 @@ void LLFloaterPostcard::sendPostcard()
 	{
 		gAssetStorage->storeAssetData(mTransactionID, LLAssetType::AT_IMAGE_JPEG, &uploadCallback, (void *)this, FALSE);
 	}
-
+	
+	// give user feedback of the event
+	gViewerWindow->playSnapshotAnimAndSound();
 	LLUploadDialog::modalUploadDialog(getString("upload_message"));
 
 	// don't destroy the window until the upload is done
diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp
index 1aba5ef92f..b310256874 100644
--- a/indra/newview/llfloatersnapshot.cpp
+++ b/indra/newview/llfloatersnapshot.cpp
@@ -1006,6 +1006,7 @@ void LLSnapshotLivePreview::saveTexture()
 				    LLFloaterPerms::getEveryonePerms(),
 				    "Snapshot : " + pos_string,
 				    callback, expected_upload_cost, userdata);
+		gViewerWindow->playSnapshotAnimAndSound();
 	}
 	else
 	{
@@ -1027,6 +1028,10 @@ BOOL LLSnapshotLivePreview::saveLocal()
 	mDataSize = 0;
 	updateSnapshot(FALSE, FALSE);
 
+	if(success)
+	{
+		gViewerWindow->playSnapshotAnimAndSound();
+	}
 	return success;
 }
 
@@ -1046,6 +1051,8 @@ void LLSnapshotLivePreview::saveWeb()
 
 	LLLandmarkActions::getRegionNameAndCoordsFromPosGlobal(gAgentCamera.getCameraPositionGlobal(),
 		boost::bind(&LLSnapshotLivePreview::regionNameCallback, this, jpg, metadata, _1, _2, _3, _4));
+
+	gViewerWindow->playSnapshotAnimAndSound();
 }
 
 void LLSnapshotLivePreview::regionNameCallback(LLImageJPEG* snapshot, LLSD& metadata, const std::string& name, S32 x, S32 y, S32 z)
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index 048691696b..237aa39e6e 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -404,6 +404,8 @@ class LLFileTakeSnapshotToDisk : public view_listener_t
 									   gSavedSettings.getBOOL("RenderUIInSnapshot"),
 									   FALSE))
 		{
+			gViewerWindow->playSnapshotAnimAndSound();
+			
 			LLPointer<LLImageFormatted> formatted;
 			switch(LLFloaterSnapshot::ESnapshotFormat(gSavedSettings.getS32("SnapshotFormat")))
 			{
-- 
cgit v1.2.3


From bae83c7eac98229271a6baf4c961fe167c74a597 Mon Sep 17 00:00:00 2001
From: Seth ProductEngine <slitovchuk@productengine.com>
Date: Fri, 10 Dec 2010 19:55:47 +0200
Subject: STORM-378 ADDITIONAL FIX REVERTED Backed out changeset: f858446d207f

---
 indra/newview/llfloatersnapshot.cpp | 2 --
 1 file changed, 2 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp
index b310256874..0931f77281 100644
--- a/indra/newview/llfloatersnapshot.cpp
+++ b/indra/newview/llfloatersnapshot.cpp
@@ -908,8 +908,6 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview )
 			previewp->mPosTakenGlobal = gAgentCamera.getCameraPositionGlobal();
 			previewp->mShineCountdown = 4; // wait a few frames to avoid animation glitch due to readback this frame
 		}
-
-		gViewerWindow->playSnapshotAnimAndSound();
 	}
 	previewp->getWindow()->decBusyCount();
 	// only show fullscreen preview when in freeze frame mode
-- 
cgit v1.2.3


From 4bab98f5cd2a815d10fe494a0a7e51cc237adb4a Mon Sep 17 00:00:00 2001
From: Monty Brandenberg <monty@lindenlab.com>
Date: Fri, 10 Dec 2010 16:05:19 -0500
Subject: ESC-228 ESC-227  Corrections for metrics counters and send-on-quit
 delivery. Wanted to avoid computing metrics for duplicate requests as much as
 possible, they artificially depress averages but missed an opportunity and
 was including them in the counts.  The non-texture case is solid. Textures
 are.... confounding still.  Do a better job of trying to send one last packet
 to the grid when quitting.  It is succeeding now, at least sometimes.  Put a
 comment in base llassetstorage.cpp pointing to cut-n-paste derivation in
 llviewerassetstorage.cpp so that changes can be replicated.  Hate doing this
 but current design forces it.

---
 indra/newview/llappviewer.cpp          | 4 +++-
 indra/newview/llviewerassetstorage.cpp | 7 ++++++-
 2 files changed, 9 insertions(+), 2 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 30005258ed..c667fba86f 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -3036,6 +3036,9 @@ void LLAppViewer::requestQuit()
 		return;
 	}
 
+	// Try to send metrics back to the grid
+	metricsSend(!gDisconnected);
+	
 	LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
 	effectp->setPositionGlobal(gAgent.getPositionGlobal());
 	effectp->setColor(LLColor4U(gAgent.getEffectColor()));
@@ -3053,7 +3056,6 @@ void LLAppViewer::requestQuit()
 	LLSideTray::getInstance()->notifyChildren(LLSD().with("request","quit"));
 
 	send_stats();
-	metricsSend(!gDisconnected);
 
 	gLogoutTimer.reset();
 	mQuitRequested = true;
diff --git a/indra/newview/llviewerassetstorage.cpp b/indra/newview/llviewerassetstorage.cpp
index 197cb3468c..36c8b42a52 100644
--- a/indra/newview/llviewerassetstorage.cpp
+++ b/indra/newview/llviewerassetstorage.cpp
@@ -348,7 +348,12 @@ void LLViewerAssetStorage::_queueDataRequest(
 		req->mDownCallback = callback;
 		req->mUserData = user_data;
 		req->mIsPriority = is_priority;
-		req->mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
+		if (!duplicate)
+		{
+			// Only collect metrics for non-duplicate requests.  Others 
+			// are piggy-backing and will artificially lower averages.
+			req->mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
+		}
 		
 		mPendingDownloads.push_back(req);
 	
-- 
cgit v1.2.3


From 11d420dd32e643a191c16b04f2fbb42c2b4db628 Mon Sep 17 00:00:00 2001
From: Monty Brandenberg <monty@lindenlab.com>
Date: Fri, 10 Dec 2010 17:41:05 -0800
Subject: Decided to refactor a bit.  Was using LLSD as an internal data
 representation transferring ownership, doing data aggregation in a very
 pedantic way.  That's just adding unneeded cost and complication.  Used the
 same objects to transport data as are collecting it and everything got
 simpler, faster, easier to read with fewer gotchas.  Bit myself *again* doing
 the min/max/mean merges but the unittests where there to pick me up again. 
 Added a per-region FPS metric while I was at it.  This is much asked for and
 there was a convenient place to sample the value.

---
 indra/newview/llappviewer.cpp                   |  31 +-
 indra/newview/llsimplestat.h                    |  18 +
 indra/newview/lltexturefetch.cpp                |  98 ++--
 indra/newview/lltexturefetch.h                  |   7 +-
 indra/newview/llviewerassetstats.cpp            | 286 ++++--------
 indra/newview/llviewerassetstats.h              |  70 ++-
 indra/newview/tests/llsimplestat_test.cpp       | 158 +++++++
 indra/newview/tests/llviewerassetstats_test.cpp | 595 ++++++++++++++----------
 8 files changed, 740 insertions(+), 523 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index c667fba86f..3640d01642 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -3804,6 +3804,11 @@ void LLAppViewer::idle()
 				llinfos << "Unknown object updates: " << gObjectList.mNumUnknownUpdates << llendl;
 				gObjectList.mNumUnknownUpdates = 0;
 			}
+
+			// ViewerMetrics FPS piggy-backing on the debug timer.
+			// The 5-second interval is nice for this purpose.  If the object debug
+			// bit moves or is disabled, please give this a suitable home.
+			LLViewerAssetStatsFF::record_fps_main(frame_rate_clamped);
 		}
 	}
 
@@ -4805,23 +4810,17 @@ void LLAppViewer::metricsSend(bool enable_reporting)
 		{
 			std::string	caps_url = regionp->getCapability("ViewerMetrics");
 
-			// *NOTE:  Pay attention here.  LLSD's are not safe for thread sharing
-			// and their ownership is difficult to transfer across threads.  We do
-			// it here by having only one reference (the new'd pointer) to the LLSD
-			// or any subtree of it.  This pointer is then transfered to the other
-			// thread using correct thread logic to do all data ordering.
-			LLSD * envelope = new LLSD(LLSD::emptyMap());
-			{
-				(*envelope) = gViewerAssetStatsMain->asLLSD();
-				(*envelope)["session_id"] = gAgentSessionID;
-				(*envelope)["agent_id"] = gAgentID;
-			}
-		
+			// Make a copy of the main stats to send into another thread.
+			// Receiving thread takes ownership.
+			LLViewerAssetStats * main_stats(new LLViewerAssetStats(*gViewerAssetStatsMain));
+			
 			// Send a report request into 'thread1' to get the rest of the data
-			// and have it sent to the stats collector.  LLSD ownership transfers
-			// with this call.
-			LLAppViewer::sTextureFetch->commandSendMetrics(caps_url, envelope);
-			envelope = 0;			// transfer noted
+			// and provide some additional parameters while here.
+			LLAppViewer::sTextureFetch->commandSendMetrics(caps_url,
+														   gAgentSessionID,
+														   gAgentID,
+														   main_stats);
+			main_stats = 0;		// Ownership transferred
 		}
 		else
 		{
diff --git a/indra/newview/llsimplestat.h b/indra/newview/llsimplestat.h
index f8f4be0390..a90e503adb 100644
--- a/indra/newview/llsimplestat.h
+++ b/indra/newview/llsimplestat.h
@@ -62,6 +62,9 @@ public:
 
 	inline void reset()					{ mCount = 0; }
 
+	inline void merge(const LLSimpleStatCounter & src)
+										{ mCount += src.mCount; }
+	
 	inline U32 operator++()				{ return ++mCount; }
 
 	inline U32 getCount() const			{ return mCount; }
@@ -125,6 +128,21 @@ public:
 			++mCount;
 		}
 
+	void merge(const LLSimpleStatMMM<VALUE_T> & src)
+		{
+			if (! mCount)
+			{
+				*this = src;
+			}
+			else if (src.mCount)
+			{
+				mMin = llmin(mMin, src.mMin);
+				mMax = llmax(mMax, src.mMax);
+				mCount += src.mCount;
+				mTotal += src.mTotal;
+			}
+		}
+	
 	inline U32 getCount() const		{ return mCount; }
 	inline Value getMin() const		{ return mMin; }
 	inline Value getMax() const		{ return mMax; }
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index 73d78c9334..e1f9d7bdcc 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -442,18 +442,18 @@ namespace
  *         |           | TE  |                   .        +-------+
  *         |           +--+--+                   .        | Thd1  |
  *         |              |                      .        |       |
- *         |  (llsd)   +-----+                   .        | Stats |
+ *         |           +-----+                   .        | Stats |
  *          `--------->| RSC |                   .        |       |
  *                     +--+--+                   .        | Coll. |
  *                        |                      .        +-------+
  *                     +--+--+                   .            |
  *                     | SME |---.               .            |
  *                     +-----+    \              .            |
- *                        .        \ (llsd)   +-----+         |
+ *                        .        \ (clone)  +-----+         |
  *                        .         `-------->| SM  |         |
  *                        .                   +--+--+         |
  *                        .                      |            |
- *                        .                   +-----+  (llsd) |
+ *                        .                   +-----+         |
  *                        .                   | RSC |<--------'
  *                        .                   +-----+
  *                        .                      |
@@ -472,11 +472,12 @@ namespace
  * SR  - Set Region.  New region UUID is sent to the thread-local
  *       collector.
  * SME - Send Metrics Enqueued.  Enqueue a 'Send Metrics' command
- *       including an ownership transfer of an LLSD.
+ *       including an ownership transfer of a cloned LLViewerAssetStats.
  *       TFReqSendMetrics carries the data.
  * SM  - Send Metrics.  Global metrics reporting operation.  Takes
- *       the remote LLSD from the command, merges it with and LLSD
- *       from the local collector and sends it to the grid.
+ *       the cloned stats from the command, merges it with the
+ *       thread's local stats, converts to LLSD and sends it on
+ *       to the grid.
  * AM  - Agent Moved.  Agent has completed some sort of move to a
  *       new region.
  * TE  - Timer Expired.  Metrics timer has expired (on the order
@@ -485,7 +486,8 @@ namespace
  * MSC - Modify Stats Collector.  State change in the thread-local
  *       collector.  Typically a region change which affects the
  *       global pointers used to find the 'current stats'.
- * RSC - Read Stats Collector.  Extract collector data in LLSD form.
+ * RSC - Read Stats Collector.  Extract collector data cloning it
+ *       (i.e. deep copy) when necessary.
  *
  */
 class TFRequest // : public LLQueuedThread::QueuedRequest
@@ -539,11 +541,12 @@ public:
  *
  * This is the big operation.  The main thread gathers metrics
  * for a period of minutes into LLViewerAssetStats and other
- * objects then builds an LLSD to represent the data.  It uses
- * this command to transfer the LLSD, content *and* ownership,
- * to the TextureFetch thread which adds its own metrics and
- * kicks of an HTTP POST of the resulting data to the currently
- * active metrics collector.
+ * objects then makes a snapshot of the data by cloning the
+ * collector.  This command transfers the clone, along with a few
+ * additional arguments (UUIDs), handing ownership to the
+ * TextureFetch thread.  It then merges its own data into the
+ * cloned copy, converts to LLSD and kicks off an HTTP POST of
+ * the resulting data to the currently active metrics collector.
  *
  * Corresponds to LLTextureFetch::commandSendMetrics()
  */
@@ -558,16 +561,24 @@ public:
 	 *							to receive the data.  Does not have to
 	 *							be associated with a particular region.
 	 *
-	 * @param	report_main		Pointer to LLSD containing main
-	 *							thread metrics.  Ownership transfers
-	 *							to the new thread using very carefully
-	 *							constructed code.
+	 * @param	session_id		UUID of the agent's session.
+	 *
+	 * @param	agent_id		UUID of the agent.  (Being pure here...)
+	 *
+	 * @param	main_stats		Pointer to a clone of the main thread's
+	 *							LLViewerAssetStats data.  Thread1 takes
+	 *							ownership of the copy and disposes of it
+	 *							when done.
 	 */
 	TFReqSendMetrics(const std::string & caps_url,
-					 LLSD * report_main)
+					 const LLUUID & session_id,
+					 const LLUUID & agent_id,
+					 LLViewerAssetStats * main_stats)
 		: TFRequest(),
 		  mCapsURL(caps_url),
-		  mReportMain(report_main)
+		  mSessionID(session_id),
+		  mAgentID(agent_id),
+		  mMainStats(main_stats)
 		{}
 	TFReqSendMetrics & operator=(const TFReqSendMetrics &);	// Not defined
 
@@ -577,7 +588,9 @@ public:
 		
 public:
 	const std::string mCapsURL;
-	LLSD * mReportMain;
+	const LLUUID mSessionID;
+	const LLUUID mAgentID;
+	LLViewerAssetStats * mMainStats;
 };
 
 /*
@@ -2727,9 +2740,11 @@ void LLTextureFetch::commandSetRegion(U64 region_handle)
 }
 
 void LLTextureFetch::commandSendMetrics(const std::string & caps_url,
-										LLSD * report_main)
+										const LLUUID & session_id,
+										const LLUUID & agent_id,
+										LLViewerAssetStats * main_stats)
 {
-	TFReqSendMetrics * req = new TFReqSendMetrics(caps_url, report_main);
+	TFReqSendMetrics * req = new TFReqSendMetrics(caps_url, session_id, agent_id, main_stats);
 
 	cmdEnqueue(req);
 }
@@ -2808,14 +2823,14 @@ TFReqSetRegion::doWork(LLTextureFetch *)
 
 TFReqSendMetrics::~TFReqSendMetrics()
 {
-	delete mReportMain;
-	mReportMain = 0;
+	delete mMainStats;
+	mMainStats = 0;
 }
 
 
 /**
  * Implements the 'Send Metrics' command.  Takes over
- * ownership of the passed LLSD pointer.
+ * ownership of the passed LLViewerAssetStats pointer.
  *
  * Thread:  Thread1 (TextureFetch)
  */
@@ -2893,33 +2908,36 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
 	static volatile bool reporting_started(false);
 	static volatile S32 report_sequence(0);
     
-	// We've already taken over ownership of the LLSD at this point
-	// and can do normal LLSD sharing operations at this point.  But
-	// still being careful, regardless.
-	LLSD & main_stats = *mReportMain;
-
-	LLSD thread1_stats = gViewerAssetStatsThread1->asLLSD();			// 'duration' & 'regions' from this LLSD
-	thread1_stats["message"] = "ViewerAssetMetrics";					// Identifies the type of metrics
-	thread1_stats["sequence"] = report_sequence;						// Sequence number
-	thread1_stats["initial"] = ! reporting_started;						// Initial data from viewer
-	thread1_stats["break"] = LLTextureFetch::svMetricsDataBreak;		// Break in data prior to this report
+	// We've taken over ownership of the stats copy at this
+	// point.  Get a working reference to it for merging here
+	// but leave it in 'this'.  Destructor will rid us of it.
+	LLViewerAssetStats & main_stats = *mMainStats;
+
+	// Merge existing stats into those from main, convert to LLSD
+	main_stats.merge(*gViewerAssetStatsThread1);
+	LLSD merged_llsd = main_stats.asLLSD();
+
+	// Add some additional meta fields to the content
+	merged_llsd["session_id"] = mSessionID;
+	merged_llsd["agent_id"] = mAgentID;
+	merged_llsd["message"] = "ViewerAssetMetrics";					// Identifies the type of metrics
+	merged_llsd["sequence"] = report_sequence;						// Sequence number
+	merged_llsd["initial"] = ! reporting_started;					// Initial data from viewer
+	merged_llsd["break"] = LLTextureFetch::svMetricsDataBreak;		// Break in data prior to this report
 		
 	// Update sequence number
 	if (S32_MAX == ++report_sequence)
 		report_sequence = 0;
 
-	// Merge the two LLSDs into a single report
-	LLViewerAssetStatsFF::merge_stats(main_stats, thread1_stats);
-
 	// Limit the size of the stats report if necessary.
-	thread1_stats["truncated"] = truncate_viewer_metrics(10, thread1_stats);
+	merged_llsd["truncated"] = truncate_viewer_metrics(10, merged_llsd);
 
 	if (! mCapsURL.empty())
 	{
 		LLCurlRequest::headers_t headers;
 		fetcher->getCurlRequest().post(mCapsURL,
 									   headers,
-									   thread1_stats,
+									   merged_llsd,
 									   new lcl_responder(report_sequence,
                                                          report_sequence,
                                                          LLTextureFetch::svMetricsDataBreak,
@@ -2933,7 +2951,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
 	// In QA mode, Metrics submode, log the result for ease of testing
 	if (fetcher->isQAMode())
 	{
-		LL_INFOS("Textures") << thread1_stats << LL_ENDL;
+		LL_INFOS("Textures") << merged_llsd << LL_ENDL;
 	}
 
 	gViewerAssetStatsThread1->reset();
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index af30d1bb3b..a8fd3ce244 100644
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -40,6 +40,8 @@ class HTTPGetResponder;
 class LLTextureCache;
 class LLImageDecodeThread;
 class LLHost;
+class LLViewerAssetStats;
+
 namespace { class TFRequest; }
 
 // Interface class
@@ -88,7 +90,10 @@ public:
 
 	// Commands available to other threads to control metrics gathering operations.
 	void commandSetRegion(U64 region_handle);
-	void commandSendMetrics(const std::string & caps_url, LLSD * report_main);
+	void commandSendMetrics(const std::string & caps_url,
+							const LLUUID & session_id,
+							const LLUUID & agent_id,
+							LLViewerAssetStats * main_stats);
 	void commandDataBreak();
 
 	LLCurlRequest & getCurlRequest()	{ return *mCurlGetRequest; }
diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp
index d798786277..399d62d2fc 100644
--- a/indra/newview/llviewerassetstats.cpp
+++ b/indra/newview/llviewerassetstats.cpp
@@ -113,11 +113,34 @@ LLViewerAssetStats::PerRegionStats::reset()
 		mRequests[i].mDequeued.reset();
 		mRequests[i].mResponse.reset();
 	}
-
+	mFPS.reset();
+	
 	mTotalTime = 0;
 	mStartTimestamp = LLViewerAssetStatsFF::get_timestamp();
 }
 
+
+void
+LLViewerAssetStats::PerRegionStats::merge(const LLViewerAssetStats::PerRegionStats & src)
+{
+	// mRegionHandle, mTotalTime, mStartTimestamp are left alone.
+	
+	// mFPS
+	if (src.mFPS.getCount() && mFPS.getCount())
+	{
+		mFPS.merge(src.mFPS);
+	}
+
+	// Requests
+	for (int i = 0; i < LL_ARRAY_SIZE(mRequests); ++i)
+	{
+		mRequests[i].mEnqueued.merge(src.mRequests[i].mEnqueued);
+		mRequests[i].mDequeued.merge(src.mRequests[i].mDequeued);
+		mRequests[i].mResponse.merge(src.mRequests[i].mResponse);
+	}
+}
+
+
 void
 LLViewerAssetStats::PerRegionStats::accumulateTime(duration_t now)
 {
@@ -136,6 +159,19 @@ LLViewerAssetStats::LLViewerAssetStats()
 }
 
 
+LLViewerAssetStats::LLViewerAssetStats(const LLViewerAssetStats & src)
+	: mRegionHandle(src.mRegionHandle),
+	  mResetTimestamp(src.mResetTimestamp)
+{
+	const PerRegionContainer::const_iterator it_end(src.mRegionStats.end());
+	for (PerRegionContainer::const_iterator it(src.mRegionStats.begin()); it_end != it; ++it)
+	{
+		mRegionStats[it->first] = new PerRegionStats(*it->second);
+	}
+	mCurRegionStats = mRegionStats[mRegionHandle];
+}
+
+
 void
 LLViewerAssetStats::reset()
 {
@@ -215,6 +251,12 @@ LLViewerAssetStats::recordGetServiced(LLViewerAssetType::EType at, bool with_htt
 	mCurRegionStats->mRequests[int(eac)].mResponse.record(duration);
 }
 
+void
+LLViewerAssetStats::recordFPS(F32 fps)
+{
+	mCurRegionStats->mFPS.record(fps);
+}
+
 LLSD
 LLViewerAssetStats::asLLSD()
 {
@@ -231,7 +273,7 @@ LLViewerAssetStats::asLLSD()
 			LLSD::String("get_other")
 		};
 
-	// Sub-tags.  If you add or delete from this list, mergeRegionsLLSD() must be updated.
+	// Stats Group Sub-tags.
 	static const LLSD::String enq_tag("enqueued");
 	static const LLSD::String deq_tag("dequeued");
 	static const LLSD::String rcnt_tag("resp_count");
@@ -239,6 +281,12 @@ LLViewerAssetStats::asLLSD()
 	static const LLSD::String rmax_tag("resp_max");
 	static const LLSD::String rmean_tag("resp_mean");
 
+	// MMM Group Sub-tags.
+	static const LLSD::String cnt_tag("count");
+	static const LLSD::String min_tag("min");
+	static const LLSD::String max_tag("max");
+	static const LLSD::String mean_tag("mean");
+
 	const duration_t now = LLViewerAssetStatsFF::get_timestamp();
 	mCurRegionStats->accumulateTime(now);
 
@@ -257,7 +305,7 @@ LLViewerAssetStats::asLLSD()
 		
 		LLSD reg_stat = LLSD::emptyMap();
 		
-		for (int i = 0; i < EVACCount; ++i)
+		for (int i = 0; i < LL_ARRAY_SIZE(tags); ++i)
 		{
 			LLSD & slot = reg_stat[tags[i]];
 			slot = LLSD::emptyMap();
@@ -269,6 +317,15 @@ LLViewerAssetStats::asLLSD()
 			slot[rmean_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMean() * 1.0e-6));
 		}
 
+		{
+			LLSD & slot = reg_stat["fps"];
+			slot = LLSD::emptyMap();
+			slot[cnt_tag] = LLSD(S32(stats.mFPS.getCount()));
+			slot[min_tag] = LLSD(F64(stats.mFPS.getMin()));
+			slot[max_tag] = LLSD(F64(stats.mFPS.getMax()));
+			slot[mean_tag] = LLSD(F64(stats.mFPS.getMean()));
+		}
+
 		reg_stat["duration"] = LLSD::Real(stats.mTotalTime * 1.0e-6);
 		std::stringstream reg_handle;
 		reg_handle.width(16);
@@ -284,181 +341,24 @@ LLViewerAssetStats::asLLSD()
 	return ret;
 }
 
-/* static */ void
-LLViewerAssetStats::mergeRegionsLLSD(const LLSD & src, LLSD & dst)
+void
+LLViewerAssetStats::merge(const LLViewerAssetStats & src)
 {
-	// Merge operator definitions
-	static const int MOP_ADD_INT(0);
-	static const int MOP_MIN_REAL(1);
-	static const int MOP_MAX_REAL(2);
-	static const int MOP_MEAN_REAL(3);	// Requires a 'mMergeOpArg' to weight the input terms
-
-	static const LLSD::String regions_key("regions");
-	static const LLSD::String resp_count_key("resp_count");
-	
-	static const struct
-		{
-			LLSD::String		mName;
-			int					mMergeOp;
-		}
-	key_list[] =
-		{
-			// Order is important below.  We modify the data in-place and
-			// so operations like MOP_MEAN_REAL which need the "resp_count"
-			// value for weighting must be performed before "resp_count"
-			// is modified or the weight will be wrong.  Key list is
-			// defined in asLLSD() and must track it.
-
-			{ "resp_mean", MOP_MEAN_REAL },
-			{ "enqueued", MOP_ADD_INT },
-			{ "dequeued", MOP_ADD_INT },
-			{ "resp_min", MOP_MIN_REAL },
-			{ "resp_max", MOP_MAX_REAL },
-			{ resp_count_key, MOP_ADD_INT }			// Keep last
-		};
+	// mRegionHandle, mCurRegionStats and mResetTimestamp are left untouched.
+	// Just merge the stats bodies
 
-	// Trivial checks
-	if (! src.has(regions_key))
+	const PerRegionContainer::const_iterator it_end(src.mRegionStats.end());
+	for (PerRegionContainer::const_iterator it(src.mRegionStats.begin()); it_end != it; ++it)
 	{
-		return;
-	}
-
-	if (! dst.has(regions_key))
-	{
-		dst[regions_key] = src[regions_key];
-		return;
-	}
-	
-	// Non-trivial cases requiring a deep merge.
-	const LLSD & root_src(src[regions_key]);
-	LLSD & root_dst(dst[regions_key]);
-	
-	const LLSD::map_const_iterator it_uuid_end(root_src.endMap());
-	for (LLSD::map_const_iterator it_uuid(root_src.beginMap()); it_uuid_end != it_uuid; ++it_uuid)
-	{
-		if (! root_dst.has(it_uuid->first))
+		PerRegionContainer::iterator dst(mRegionStats.find(it->first));
+		if (mRegionStats.end() == dst)
 		{
-			// src[<region>] without matching dst[<region>]
-			root_dst[it_uuid->first] = it_uuid->second;
+			// Destination is missing data, just make a private copy
+			mRegionStats[it->first] = new PerRegionStats(*it->second);
 		}
 		else
 		{
-			// src[<region>] with matching dst[<region>]
-			// We have matching source and destination regions.
-			// Now iterate over each asset bin in the region status.  Could iterate over
-			// an explicit list but this will do as well.
-			LLSD & reg_dst(root_dst[it_uuid->first]);
-			const LLSD & reg_src(root_src[it_uuid->first]);
-
-			const LLSD::map_const_iterator it_sets_end(reg_src.endMap());
-			for (LLSD::map_const_iterator it_sets(reg_src.beginMap()); it_sets_end != it_sets; ++it_sets)
-			{
-				static const LLSD::String no_touch_1("duration");
-
-				if (no_touch_1 == it_sets->first)
-				{
-					continue;
-				}
-				else if (! reg_dst.has(it_sets->first))
-				{
-					// src[<region>][<asset>] without matching dst[<region>][<asset>]
-					reg_dst[it_sets->first] = it_sets->second;
-				}
-				else
-				{
-					// src[<region>][<asset>] with matching dst[<region>][<asset>]
-					// Matching stats bin in both source and destination regions.
-					// Iterate over those bin keys we know how to merge, leave the remainder untouched.
-					LLSD & bin_dst(reg_dst[it_sets->first]);
-					const LLSD & bin_src(reg_src[it_sets->first]);
-
-					// The "resp_count" value is needed repeatedly in operations.
-					const LLSD::Integer bin_src_count(bin_src[resp_count_key].asInteger());
-					const LLSD::Integer bin_dst_count(bin_dst[resp_count_key].asInteger());
-			
-					for (int key_index(0); key_index < LL_ARRAY_SIZE(key_list); ++key_index)
-					{
-						const LLSD::String & key_name(key_list[key_index].mName);
-						
-						if (! bin_src.has(key_name))
-						{
-							// Missing src[<region>][<asset>][<field>]
-							continue;
-						}
-
-						const LLSD & src_value(bin_src[key_name]);
-				
-						if (! bin_dst.has(key_name))
-						{
-							// src[<region>][<asset>][<field>] without matching dst[<region>][<asset>][<field>]
-							bin_dst[key_name] = src_value;
-						}
-						else
-						{
-							// src[<region>][<asset>][<field>] with matching dst[<region>][<asset>][<field>]
-							LLSD & dst_value(bin_dst[key_name]);
-					
-							switch (key_list[key_index].mMergeOp)
-							{
-							case MOP_ADD_INT:
-								// Simple counts, just add
-								dst_value = dst_value.asInteger() + src_value.asInteger();
-								break;
-						
-							case MOP_MIN_REAL:
-								// Minimum
-								if (bin_src_count)
-								{
-									// If src has non-zero count, it's min is meaningful
-									if (bin_dst_count)
-									{
-										dst_value = llmin(dst_value.asReal(), src_value.asReal());
-									}
-									else
-									{
-										dst_value = src_value;
-									}
-								}
-								break;
-
-							case MOP_MAX_REAL:
-								// Maximum
-								if (bin_src_count)
-								{
-									// If src has non-zero count, it's max is meaningful
-									if (bin_dst_count)
-									{
-										dst_value = llmax(dst_value.asReal(), src_value.asReal());
-									}
-									else
-									{
-										dst_value = src_value;
-									}
-								}
-								break;
-
-							case MOP_MEAN_REAL:
-							    {
-									// Mean
-									F64 src_weight(bin_src_count);
-									F64 dst_weight(bin_dst_count);
-									F64 tot_weight(src_weight + dst_weight);
-									if (tot_weight >= F64(0.5))
-									{
-										dst_value = (((dst_value.asReal() * dst_weight)
-													  + (src_value.asReal() * src_weight))
-													 / tot_weight);
-									}
-								}
-								break;
-						
-							default:
-								break;
-							}
-						}
-					}
-				}
-			}
+			dst->second->merge(*it->second);
 		}
 	}
 }
@@ -526,6 +426,15 @@ record_response_main(LLViewerAssetType::EType at, bool with_http, bool is_temp,
 	gViewerAssetStatsMain->recordGetServiced(at, with_http, is_temp, duration);
 }
 
+void
+record_fps_main(F32 fps)
+{
+	if (! gViewerAssetStatsMain)
+		return;
+
+	gViewerAssetStatsMain->recordFPS(fps);
+}
+
 
 // 'thread1' - should be for TextureFetch thread
 
@@ -590,41 +499,6 @@ cleanup()
 }
 
 
-void
-merge_stats(const LLSD & src, LLSD & dst)
-{
-	static const LLSD::String regions_key("regions");
-
-	// Trivial cases first
-	if (! src.isMap())
-	{
-		return;
-	}
-
-	if (! dst.isMap())
-	{
-		dst = src;
-		return;
-	}
-	
-	// Okay, both src and dst are maps at this point.
-	// Collector class know how to merge the regions part.
-	LLViewerAssetStats::mergeRegionsLLSD(src, dst);
-
-	// Now merge non-regions bits manually.
-	const LLSD::map_const_iterator it_end(src.endMap());
-	for (LLSD::map_const_iterator it(src.beginMap()); it_end != it; ++it)
-	{
-		if (regions_key == it->first)
-			continue;
-
-		if (dst.has(it->first))
-			continue;
-
-		dst[it->first] = it->second;
-	}
-}
-
 } // namespace LLViewerAssetStatsFF
 
 
diff --git a/indra/newview/llviewerassetstats.h b/indra/newview/llviewerassetstats.h
index ed2d0f3922..af6bf5b695 100644
--- a/indra/newview/llviewerassetstats.h
+++ b/indra/newview/llviewerassetstats.h
@@ -125,29 +125,48 @@ public:
 			{
 				reset();
 			}
+
+		PerRegionStats(const PerRegionStats & src)
+			: LLRefCount(),
+			  mRegionHandle(src.mRegionHandle),
+			  mTotalTime(src.mTotalTime),
+			  mStartTimestamp(src.mStartTimestamp),
+			  mFPS(src.mFPS)
+			{
+				for (int i = 0; i < LL_ARRAY_SIZE(mRequests); ++i)
+				{
+					mRequests[i] = src.mRequests[i];
+				}
+			}
+
 		// Default assignment and destructor are correct.
 		
 		void reset();
 
+		void merge(const PerRegionStats & src);
+		
 		// Apply current running time to total and reset start point.
 		// Return current timestamp as a convenience.
 		void accumulateTime(duration_t now);
 		
 	public:
-		region_handle_t mRegionHandle;
-		duration_t mTotalTime;
-		duration_t mStartTimestamp;
+		region_handle_t		mRegionHandle;
+		duration_t			mTotalTime;
+		duration_t			mStartTimestamp;
+		LLSimpleStatMMM<>	mFPS;
 		
 		struct
 		{
 			LLSimpleStatCounter			mEnqueued;
 			LLSimpleStatCounter			mDequeued;
 			LLSimpleStatMMM<duration_t>	mResponse;
-		} mRequests [EVACCount];
+		}
+		mRequests [EVACCount];
 	};
 
 public:
 	LLViewerAssetStats();
+	LLViewerAssetStats(const LLViewerAssetStats &);
 	// Default destructor is correct.
 	LLViewerAssetStats & operator=(const LLViewerAssetStats &);			// Not defined
 
@@ -165,6 +184,18 @@ public:
 	void recordGetDequeued(LLViewerAssetType::EType at, bool with_http, bool is_temp);
 	void recordGetServiced(LLViewerAssetType::EType at, bool with_http, bool is_temp, duration_t duration);
 
+	// Frames-Per-Second Samples
+	void recordFPS(F32 fps);
+
+	// Merge a source instance into a destination instance.  This is
+	// conceptually an 'operator+=()' method:
+	// - counts are added
+	// - minimums are min'd
+	// - maximums are max'd
+	// - other scalars are ignored ('this' wins)
+	//
+	void merge(const LLViewerAssetStats & src);
+	
 	// Retrieve current metrics for all visited regions (NULL region UUID/handle excluded)
     // Returned LLSD is structured as follows:
 	//
@@ -177,11 +208,19 @@ public:
 	//   resp_mean  : float
 	// }
 	//
+	// &mmm_group = {
+	//   count : int,
+	//   min   : float,
+	//   max   : float,
+	//   mean  : float
+	// }
+	//
 	// {
 	//   duration: int
 	//   regions: {
 	//     $: {			// Keys are strings of the region's handle in hex
 	//       duration:                 : int,
+	//		 fps:					   : &mmm_group,
 	//       get_texture_temp_http     : &stats_group,
 	//       get_texture_temp_udp      : &stats_group,
 	//       get_texture_non_temp_http : &stats_group,
@@ -195,15 +234,6 @@ public:
 	// }
 	LLSD asLLSD();
 
-	// Merges the "regions" maps in two LLSDs structured as per asLLSD().
-	// This takes two LLSDs as returned by asLLSD() and intelligently
-	// merges the metrics contained in the maps indexed by "regions".
-	// The remainder of the top-level map of the LLSDs is left unchanged
-	// in expectation that callers will add other information at this
-	// level.  The "regions" information must be correctly formed or the
-	// final result is undefined (little defensive action).
-	static void mergeRegionsLLSD(const LLSD & src, LLSD & dst);
-
 protected:
 	typedef std::map<region_handle_t, LLPointer<PerRegionStats> > PerRegionContainer;
 
@@ -278,6 +308,8 @@ void record_dequeue_main(LLViewerAssetType::EType at, bool with_http, bool is_te
 void record_response_main(LLViewerAssetType::EType at, bool with_http, bool is_temp,
 						  LLViewerAssetStats::duration_t duration);
 
+void record_fps_main(F32 fps);
+
 
 /**
  * Region context, event and duration loggers for Thread 1.
@@ -291,18 +323,6 @@ void record_dequeue_thread1(LLViewerAssetType::EType at, bool with_http, bool is
 void record_response_thread1(LLViewerAssetType::EType at, bool with_http, bool is_temp,
 						  LLViewerAssetStats::duration_t duration);
 
-/**
- * @brief Merge two LLSD reports from different collector instances
- *
- * Use this to merge the LLSD's from two threads.  For top-level,
- * non-region data the destination (dst) is considered authoritative
- * if the key is present in both source and destination.  For
- * regions, a numerical merge is performed when data are present in
- * both source and destination and the 'right thing' is done for
- * counts, minimums, maximums and averages.
- */
-void merge_stats(const LLSD & src, LLSD & dst);
-
 } // namespace LLViewerAssetStatsFF
 
 #endif // LL_LLVIEWERASSETSTATUS_H
diff --git a/indra/newview/tests/llsimplestat_test.cpp b/indra/newview/tests/llsimplestat_test.cpp
index 5efc9cf857..60a8cac995 100644
--- a/indra/newview/tests/llsimplestat_test.cpp
+++ b/indra/newview/tests/llsimplestat_test.cpp
@@ -425,4 +425,162 @@ namespace tut
 		ensure("Overflowed MMM<U64> has huge max", (bignum == m1.getMax()));
 		ensure("Overflowed MMM<U64> has fetchable mean", (zero == m1.getMean() || true));
 	}
+
+    // Testing LLSimpleStatCounter's merge() method
+	template<> template<>
+	void stat_counter_index_object_t::test<12>()
+	{
+		LLSimpleStatCounter c1;
+		LLSimpleStatCounter c2;
+
+		++c1;
+		++c1;
+		++c1;
+		++c1;
+
+		++c2;
+		++c2;
+		c2.merge(c1);
+		
+		ensure_equals("4 merged into 2 results in 6", 6, c2.getCount());
+
+		ensure_equals("Source of merge is undamaged", 4, c1.getCount());
+	}
+
+    // Testing LLSimpleStatMMM's merge() method
+	template<> template<>
+	void stat_counter_index_object_t::test<13>()
+	{
+		LLSimpleStatMMM<> m1;
+		LLSimpleStatMMM<> m2;
+
+		m1.record(3.5);
+		m1.record(4.5);
+		m1.record(5.5);
+		m1.record(6.5);
+
+		m2.record(5.0);
+		m2.record(7.0);
+		m2.record(9.0);
+		
+		m2.merge(m1);
+
+		ensure_equals("Count after merge (p1)", 7, m2.getCount());
+		ensure_approximately_equals("Min after merge (p1)", F32(3.5), m2.getMin(), 22);
+		ensure_approximately_equals("Max after merge (p1)", F32(9.0), m2.getMax(), 22);
+		ensure_approximately_equals("Mean after merge (p1)", F32(41.000/7.000), m2.getMean(), 22);
+		
+
+		ensure_equals("Source count of merge is undamaged (p1)", 4, m1.getCount());
+		ensure_approximately_equals("Source min of merge is undamaged (p1)", F32(3.5), m1.getMin(), 22);
+		ensure_approximately_equals("Source max of merge is undamaged (p1)", F32(6.5), m1.getMax(), 22);
+		ensure_approximately_equals("Source mean of merge is undamaged (p1)", F32(5.0), m1.getMean(), 22);
+
+		m2.reset();
+
+		m2.record(-22.0);
+		m2.record(-1.0);
+		m2.record(30.0);
+		
+		m2.merge(m1);
+
+		ensure_equals("Count after merge (p2)", 7, m2.getCount());
+		ensure_approximately_equals("Min after merge (p2)", F32(-22.0), m2.getMin(), 22);
+		ensure_approximately_equals("Max after merge (p2)", F32(30.0), m2.getMax(), 22);
+		ensure_approximately_equals("Mean after merge (p2)", F32(27.000/7.000), m2.getMean(), 22);
+
+	}
+
+    // Testing LLSimpleStatMMM's merge() method when src contributes nothing
+	template<> template<>
+	void stat_counter_index_object_t::test<14>()
+	{
+		LLSimpleStatMMM<> m1;
+		LLSimpleStatMMM<> m2;
+
+		m2.record(5.0);
+		m2.record(7.0);
+		m2.record(9.0);
+		
+		m2.merge(m1);
+
+		ensure_equals("Count after merge (p1)", 3, m2.getCount());
+		ensure_approximately_equals("Min after merge (p1)", F32(5.0), m2.getMin(), 22);
+		ensure_approximately_equals("Max after merge (p1)", F32(9.0), m2.getMax(), 22);
+		ensure_approximately_equals("Mean after merge (p1)", F32(7.000), m2.getMean(), 22);
+
+		ensure_equals("Source count of merge is undamaged (p1)", 0, m1.getCount());
+		ensure_approximately_equals("Source min of merge is undamaged (p1)", F32(0), m1.getMin(), 22);
+		ensure_approximately_equals("Source max of merge is undamaged (p1)", F32(0), m1.getMax(), 22);
+		ensure_approximately_equals("Source mean of merge is undamaged (p1)", F32(0), m1.getMean(), 22);
+
+		m2.reset();
+
+		m2.record(-22.0);
+		m2.record(-1.0);
+		
+		m2.merge(m1);
+
+		ensure_equals("Count after merge (p2)", 2, m2.getCount());
+		ensure_approximately_equals("Min after merge (p2)", F32(-22.0), m2.getMin(), 22);
+		ensure_approximately_equals("Max after merge (p2)", F32(-1.0), m2.getMax(), 22);
+		ensure_approximately_equals("Mean after merge (p2)", F32(-11.5), m2.getMean(), 22);
+	}
+
+    // Testing LLSimpleStatMMM's merge() method when dst contributes nothing
+	template<> template<>
+	void stat_counter_index_object_t::test<15>()
+	{
+		LLSimpleStatMMM<> m1;
+		LLSimpleStatMMM<> m2;
+
+		m1.record(5.0);
+		m1.record(7.0);
+		m1.record(9.0);
+		
+		m2.merge(m1);
+
+		ensure_equals("Count after merge (p1)", 3, m2.getCount());
+		ensure_approximately_equals("Min after merge (p1)", F32(5.0), m2.getMin(), 22);
+		ensure_approximately_equals("Max after merge (p1)", F32(9.0), m2.getMax(), 22);
+		ensure_approximately_equals("Mean after merge (p1)", F32(7.000), m2.getMean(), 22);
+
+		ensure_equals("Source count of merge is undamaged (p1)", 3, m1.getCount());
+		ensure_approximately_equals("Source min of merge is undamaged (p1)", F32(5.0), m1.getMin(), 22);
+		ensure_approximately_equals("Source max of merge is undamaged (p1)", F32(9.0), m1.getMax(), 22);
+		ensure_approximately_equals("Source mean of merge is undamaged (p1)", F32(7.0), m1.getMean(), 22);
+
+		m1.reset();
+		m2.reset();
+		
+		m1.record(-22.0);
+		m1.record(-1.0);
+		
+		m2.merge(m1);
+
+		ensure_equals("Count after merge (p2)", 2, m2.getCount());
+		ensure_approximately_equals("Min after merge (p2)", F32(-22.0), m2.getMin(), 22);
+		ensure_approximately_equals("Max after merge (p2)", F32(-1.0), m2.getMax(), 22);
+		ensure_approximately_equals("Mean after merge (p2)", F32(-11.5), m2.getMean(), 22);
+	}
+
+    // Testing LLSimpleStatMMM's merge() method when neither dst nor src contributes
+	template<> template<>
+	void stat_counter_index_object_t::test<16>()
+	{
+		LLSimpleStatMMM<> m1;
+		LLSimpleStatMMM<> m2;
+
+		m2.merge(m1);
+
+		ensure_equals("Count after merge (p1)", 0, m2.getCount());
+		ensure_approximately_equals("Min after merge (p1)", F32(0), m2.getMin(), 22);
+		ensure_approximately_equals("Max after merge (p1)", F32(0), m2.getMax(), 22);
+		ensure_approximately_equals("Mean after merge (p1)", F32(0), m2.getMean(), 22);
+
+		ensure_equals("Source count of merge is undamaged (p1)", 0, m1.getCount());
+		ensure_approximately_equals("Source min of merge is undamaged (p1)", F32(0), m1.getMin(), 22);
+		ensure_approximately_equals("Source max of merge is undamaged (p1)", F32(0), m1.getMax(), 22);
+		ensure_approximately_equals("Source mean of merge is undamaged (p1)", F32(0), m1.getMean(), 22);
+	}
 }
diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp
index 153056b3cd..9c54266017 100644
--- a/indra/newview/tests/llviewerassetstats_test.cpp
+++ b/indra/newview/tests/llviewerassetstats_test.cpp
@@ -44,6 +44,7 @@
 static const char * all_keys[] = 
 {
 	"duration",
+	"fps",
 	"get_other",
 	"get_texture_temp_http",
 	"get_texture_temp_udp",
@@ -76,6 +77,19 @@ static const char * sub_keys[] =
 	"resp_mean"
 };
 
+static const char * mmm_resp_keys[] = 
+{
+	"fps"
+};
+
+static const char * mmm_sub_keys[] =
+{
+	"count",
+	"max",
+	"min",
+	"mean"
+};
+
 static const LLUUID region1("4e2d81a3-6263-6ffe-ad5c-8ce04bee07e8");
 static const LLUUID region2("68762cc8-b68b-4e45-854b-e830734f2d4a");
 static const U64 region1_handle(0x00000401000003f7ULL);
@@ -172,6 +186,15 @@ namespace tut
 				ensure(line, sd[resp_keys[i]].has(sub_keys[j]));
 			}
 		}
+
+		for (int i = 0; i < LL_ARRAY_SIZE(mmm_resp_keys); ++i)
+		{
+			for (int j = 0; j < LL_ARRAY_SIZE(mmm_sub_keys); ++j)
+			{
+				std::string line = llformat("Key '%s' has '%s' key", mmm_resp_keys[i], mmm_sub_keys[j]);
+				ensure(line, sd[mmm_resp_keys[i]].has(mmm_sub_keys[j]));
+			}
+		}
 	}
 
 	// Create a non-global instance and check some content
@@ -461,293 +484,395 @@ namespace tut
 		ensure("sd[get_gesture_udp][dequeued] is reset", (0 == sd["get_gesture_udp"]["dequeued"].asInteger()));
 	}
 
-	// Check that the LLSD merger knows what it's doing (basic test)
+
+	// LLViewerAssetStats::merge() basic functions work
 	template<> template<>
 	void tst_viewerassetstats_index_object_t::test<9>()
 	{
-		LLSD::String reg1_name = region1_handle_str;
-		LLSD::String reg2_name = region2_handle_str;
-
-		LLSD reg1_stats = LLSD::emptyMap();
-		LLSD reg2_stats = LLSD::emptyMap();
-
-		LLSD & tmp_other1 = reg1_stats["get_other"];
-		tmp_other1["enqueued"] = 4;
-		tmp_other1["dequeued"] = 4;
-		tmp_other1["resp_count"] = 8;
-		tmp_other1["resp_max"] = F64(23.2892);
-		tmp_other1["resp_min"] = F64(0.2829);
-		tmp_other1["resp_mean"] = F64(2.298928);
-
-		LLSD & tmp_other2 = reg2_stats["get_other"];
-		tmp_other2["enqueued"] = 8;
-		tmp_other2["dequeued"] = 7;
-		tmp_other2["resp_count"] = 3;
-		tmp_other2["resp_max"] = F64(6.5);
-		tmp_other2["resp_min"] = F64(0.01);
-		tmp_other2["resp_mean"] = F64(4.1);
+		LLViewerAssetStats s1;
+		LLViewerAssetStats s2;
+
+		s1.setRegion(region1_handle);
+		s2.setRegion(region1_handle);
+
+		s1.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 5000000);
+		s1.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 6000000);
+		s1.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 8000000);
+		s1.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 7000000);
+		s1.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 9000000);
 		
-		{
-			LLSD src = LLSD::emptyMap();
-			LLSD dst = LLSD::emptyMap();
+		s2.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 2000000);
+		s2.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 3000000);
+		s2.recordGetServiced(LLViewerAssetType::AT_TEXTURE, true, true, 4000000);
 
-			src["regions"][reg1_name] = reg1_stats;
-			src["duration"] = 24;
-			dst["regions"][reg2_name] = reg2_stats;
-			dst["duration"] = 36;
+		s2.merge(s1);
 
-			LLViewerAssetStats::mergeRegionsLLSD(src, dst);
+		LLSD s2_llsd = s2.asLLSD();
 		
-			ensure("region 1 in merged stats", llsd_equals(reg1_stats, dst["regions"][reg1_name]));
-			ensure("region 2 still in merged stats", llsd_equals(reg2_stats, dst["regions"][reg2_name]));
-		}
+		ensure_equals("count after merge", 8, s2_llsd["regions"][region1_handle_str]["get_texture_temp_http"]["resp_count"].asInteger());
+		ensure_approximately_equals("min after merge", 2.0, s2_llsd["regions"][region1_handle_str]["get_texture_temp_http"]["resp_min"].asReal(), 22);
+		ensure_approximately_equals("max after merge", 9.0, s2_llsd["regions"][region1_handle_str]["get_texture_temp_http"]["resp_max"].asReal(), 22);
+		ensure_approximately_equals("max after merge", 5.5, s2_llsd["regions"][region1_handle_str]["get_texture_temp_http"]["resp_mean"].asReal(), 22);
 
-		{
-			LLSD src = LLSD::emptyMap();
-			LLSD dst = LLSD::emptyMap();
-
-			src["regions"][reg1_name] = reg1_stats;
-			src["duration"] = 24;
-			dst["regions"][reg1_name] = reg2_stats;
-			dst["duration"] = 36;
-
-			LLViewerAssetStats::mergeRegionsLLSD(src, dst);
-
-			ensure("src not ruined", llsd_equals(reg1_stats, src["regions"][reg1_name]));
-			ensure_equals("added enqueued counts", dst["regions"][reg1_name]["get_other"]["enqueued"].asInteger(), 12);
-			ensure_equals("added dequeued counts", dst["regions"][reg1_name]["get_other"]["dequeued"].asInteger(), 11);
-			ensure_equals("added response counts", dst["regions"][reg1_name]["get_other"]["resp_count"].asInteger(), 11);
-			ensure_approximately_equals("min'd minimum response times", dst["regions"][reg1_name]["get_other"]["resp_min"].asReal(), 0.01, 20);
-			ensure_approximately_equals("max'd maximum response times", dst["regions"][reg1_name]["get_other"]["resp_max"].asReal(), 23.2892, 20);
-			ensure_approximately_equals("weighted mean of means", dst["regions"][reg1_name]["get_other"]["resp_mean"].asReal(), 2.7901295, 20);
-		}
 	}
 
-	// Maximum merges are interesting when one side contributes nothing
+	// LLViewerAssetStats::merge() basic functions work without corrupting source data
 	template<> template<>
 	void tst_viewerassetstats_index_object_t::test<10>()
 	{
-		LLSD::String reg1_name = region1_handle_str;
-		LLSD::String reg2_name = region2_handle_str;
-
-		LLSD reg1_stats = LLSD::emptyMap();
-		LLSD reg2_stats = LLSD::emptyMap();
-
-		LLSD & tmp_other1 = reg1_stats["get_other"];
-		tmp_other1["enqueued"] = 4;
-		tmp_other1["dequeued"] = 4;
-		tmp_other1["resp_count"] = 7;
-		tmp_other1["resp_max"] = F64(-23.2892);
-		tmp_other1["resp_min"] = F64(-123.2892);
-		tmp_other1["resp_mean"] = F64(-58.28298);
-
-		LLSD & tmp_other2 = reg2_stats["get_other"];
-		tmp_other2["enqueued"] = 8;
-		tmp_other2["dequeued"] = 7;
-		tmp_other2["resp_count"] = 0;
-		tmp_other2["resp_max"] = F64(0);
-		tmp_other2["resp_min"] = F64(0);
-		tmp_other2["resp_mean"] = F64(0);
-		
-		{
-			LLSD src = LLSD::emptyMap();
-			LLSD dst = LLSD::emptyMap();
+		LLViewerAssetStats s1;
+		LLViewerAssetStats s2;
 
-			src["regions"][reg1_name] = reg1_stats;
-			src["duration"] = 24;
-			dst["regions"][reg1_name] = reg2_stats;
-			dst["duration"] = 36;
+		s1.setRegion(region1_handle);
+		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
 
-			LLViewerAssetStats::mergeRegionsLLSD(src, dst);
-		
-			ensure_approximately_equals("dst maximum with count 0 does not contribute to merged maximum",
-										dst["regions"][reg1_name]["get_other"]["resp_max"].asReal(), F64(-23.2892), 20);
-		}
-
-		{
-			LLSD src = LLSD::emptyMap();
-			LLSD dst = LLSD::emptyMap();
+		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
 
-			src["regions"][reg1_name] = reg2_stats;
-			src["duration"] = 24;
-			dst["regions"][reg1_name] = reg1_stats;
-			dst["duration"] = 36;
+		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 23289200);
+		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 282900);
 
-			LLViewerAssetStats::mergeRegionsLLSD(src, dst);
 		
-			ensure_approximately_equals("src maximum with count 0 does not contribute to merged maximum",
-										dst["regions"][reg1_name]["get_other"]["resp_max"].asReal(), F64(-23.2892), 20);
-		}
-	}
+		s2.setRegion(region2_handle);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+		s2.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 6500000);
+		s2.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 10000);
 
-    // Minimum merges are interesting when one side contributes nothing
-	template<> template<>
-	void tst_viewerassetstats_index_object_t::test<11>()
-	{
-		LLSD::String reg1_name = region1_handle_str;
-		LLSD::String reg2_name = region2_handle_str;
-
-		LLSD reg1_stats = LLSD::emptyMap();
-		LLSD reg2_stats = LLSD::emptyMap();
-
-		LLSD & tmp_other1 = reg1_stats["get_other"];
-		tmp_other1["enqueued"] = 4;
-		tmp_other1["dequeued"] = 4;
-		tmp_other1["resp_count"] = 7;
-		tmp_other1["resp_max"] = F64(123.2892);
-		tmp_other1["resp_min"] = F64(23.2892);
-		tmp_other1["resp_mean"] = F64(58.28298);
-
-		LLSD & tmp_other2 = reg2_stats["get_other"];
-		tmp_other2["enqueued"] = 8;
-		tmp_other2["dequeued"] = 7;
-		tmp_other2["resp_count"] = 0;
-		tmp_other2["resp_max"] = F64(0);
-		tmp_other2["resp_min"] = F64(0);
-		tmp_other2["resp_mean"] = F64(0);
-		
 		{
-			LLSD src = LLSD::emptyMap();
-			LLSD dst = LLSD::emptyMap();
-
-			src["regions"][reg1_name] = reg1_stats;
-			src["duration"] = 24;
-			dst["regions"][reg1_name] = reg2_stats;
-			dst["duration"] = 36;
+			s2.merge(s1);
+			
+			LLSD src = s1.asLLSD();
+			LLSD dst = s2.asLLSD();
+
+			// Remove time stamps, they're a problem
+			src.erase("duration");
+			src["regions"][region1_handle_str].erase("duration");
+			dst.erase("duration");
+			dst["regions"][region1_handle_str].erase("duration");
+			dst["regions"][region2_handle_str].erase("duration");
+
+			ensure_equals("merge src has single region", 1, src["regions"].size());
+			ensure_equals("merge dst has dual regions", 2, dst["regions"].size());
+			ensure("result from src is in dst", llsd_equals(src["regions"][region1_handle_str],
+															dst["regions"][region1_handle_str]));
+		}
 
-			LLViewerAssetStats::mergeRegionsLLSD(src, dst);
+		s1.setRegion(region1_handle);
+		s2.setRegion(region1_handle);
+		s1.reset();
+		s2.reset();
 		
-			ensure_approximately_equals("dst minimum with count 0 does not contribute to merged minimum",
-										dst["regions"][reg1_name]["get_other"]["resp_min"].asReal(), F64(23.2892), 20);
-		}
+		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
 
-		{
-			LLSD src = LLSD::emptyMap();
-			LLSD dst = LLSD::emptyMap();
+		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
 
-			src["regions"][reg1_name] = reg2_stats;
-			src["duration"] = 24;
-			dst["regions"][reg1_name] = reg1_stats;
-			dst["duration"] = 36;
+		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 23289200);
+		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 282900);
 
-			LLViewerAssetStats::mergeRegionsLLSD(src, dst);
 		
-			ensure_approximately_equals("src minimum with count 0 does not contribute to merged minimum",
-										dst["regions"][reg1_name]["get_other"]["resp_min"].asReal(), F64(23.2892), 20);
+		s2.setRegion(region1_handle);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+		s2.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 6500000);
+		s2.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 10000);
+
+		{
+			s2.merge(s1);
+			
+			LLSD src = s1.asLLSD();
+			LLSD dst = s2.asLLSD();
+
+			// Remove time stamps, they're a problem
+			src.erase("duration");
+			src["regions"][region1_handle_str].erase("duration");
+			dst.erase("duration");
+			dst["regions"][region1_handle_str].erase("duration");
+
+			ensure_equals("src counts okay (enq)", 4, src["regions"][region1_handle_str]["get_other"]["enqueued"].asInteger());
+			ensure_equals("src counts okay (deq)", 4, src["regions"][region1_handle_str]["get_other"]["dequeued"].asInteger());
+			ensure_equals("src resp counts okay", 2, src["regions"][region1_handle_str]["get_other"]["resp_count"].asInteger());
+			ensure_approximately_equals("src respmin okay", 0.2829, src["regions"][region1_handle_str]["get_other"]["resp_min"].asReal(), 20);
+			ensure_approximately_equals("src respmax okay", 23.2892, src["regions"][region1_handle_str]["get_other"]["resp_max"].asReal(), 20);
+			
+			ensure_equals("dst counts okay (enq)", 12, dst["regions"][region1_handle_str]["get_other"]["enqueued"].asInteger());
+			ensure_equals("src counts okay (deq)", 11, dst["regions"][region1_handle_str]["get_other"]["dequeued"].asInteger());
+			ensure_equals("dst resp counts okay", 4, dst["regions"][region1_handle_str]["get_other"]["resp_count"].asInteger());
+			ensure_approximately_equals("dst respmin okay", 0.010, dst["regions"][region1_handle_str]["get_other"]["resp_min"].asReal(), 20);
+			ensure_approximately_equals("dst respmax okay", 23.2892, dst["regions"][region1_handle_str]["get_other"]["resp_max"].asReal(), 20);
 		}
 	}
 
-    // resp_count missing is taken as '0' for maximum calculation
+
+    // Maximum merges are interesting when one side contributes nothing
 	template<> template<>
-	void tst_viewerassetstats_index_object_t::test<12>()
+	void tst_viewerassetstats_index_object_t::test<11>()
 	{
-		LLSD::String reg1_name = region1_handle_str;
-		LLSD::String reg2_name = region2_handle_str;
-
-		LLSD reg1_stats = LLSD::emptyMap();
-		LLSD reg2_stats = LLSD::emptyMap();
-
-		LLSD & tmp_other1 = reg1_stats["get_other"];
-		tmp_other1["enqueued"] = 4;
-		tmp_other1["dequeued"] = 4;
-		tmp_other1["resp_count"] = 7;
-		tmp_other1["resp_max"] = F64(-23.2892);
-		tmp_other1["resp_min"] = F64(-123.2892);
-		tmp_other1["resp_mean"] = F64(-58.28298);
-
-		LLSD & tmp_other2 = reg2_stats["get_other"];
-		tmp_other2["enqueued"] = 8;
-		tmp_other2["dequeued"] = 7;
-		// tmp_other2["resp_count"] = 0;
-		tmp_other2["resp_max"] = F64(0);
-		tmp_other2["resp_min"] = F64(0);
-		tmp_other2["resp_mean"] = F64(0);
-		
+		LLViewerAssetStats s1;
+		LLViewerAssetStats s2;
+
+		s1.setRegion(region1_handle);
+		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+		// Want to test negative numbers here but have to work in U64
+		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 0);
+		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 0);
+		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 0);
+
+		s2.setRegion(region1_handle);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
 		{
-			LLSD src = LLSD::emptyMap();
-			LLSD dst = LLSD::emptyMap();
+			s2.merge(s1);
+			
+			LLSD src = s1.asLLSD();
+			LLSD dst = s2.asLLSD();
 
-			src["regions"][reg1_name] = reg1_stats;
-			src["duration"] = 24;
-			dst["regions"][reg1_name] = reg2_stats;
-			dst["duration"] = 36;
+			// Remove time stamps, they're a problem
+			src.erase("duration");
+			src["regions"][region1_handle_str].erase("duration");
+			dst.erase("duration");
+			dst["regions"][region1_handle_str].erase("duration");
 
-			LLViewerAssetStats::mergeRegionsLLSD(src, dst);
-		
-			ensure_approximately_equals("dst maximum with undefined count does not contribute to merged maximum",
-										dst["regions"][reg1_name]["get_other"]["resp_max"].asReal(), F64(-23.2892), 20);
+			ensure_equals("dst counts come from src only", 3, dst["regions"][region1_handle_str]["get_other"]["resp_count"].asInteger());
+
+			ensure_approximately_equals("dst maximum with count 0 does not contribute to merged maximum",
+										dst["regions"][region1_handle_str]["get_other"]["resp_max"].asReal(), F64(0.0), 20);
 		}
 
+		// Other way around
+		s1.setRegion(region1_handle);
+		s2.setRegion(region1_handle);
+		s1.reset();
+		s2.reset();
+
+		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+		// Want to test negative numbers here but have to work in U64
+		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 0);
+		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 0);
+		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 0);
+
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
 		{
-			LLSD src = LLSD::emptyMap();
-			LLSD dst = LLSD::emptyMap();
+			s1.merge(s2);
+			
+			LLSD src = s2.asLLSD();
+			LLSD dst = s1.asLLSD();
 
-			src["regions"][reg1_name] = reg2_stats;
-			src["duration"] = 24;
-			dst["regions"][reg1_name] = reg1_stats;
-			dst["duration"] = 36;
+			// Remove time stamps, they're a problem
+			src.erase("duration");
+			src["regions"][region1_handle_str].erase("duration");
+			dst.erase("duration");
+			dst["regions"][region1_handle_str].erase("duration");
 
-			LLViewerAssetStats::mergeRegionsLLSD(src, dst);
-		
-			ensure_approximately_equals("src maximum with undefined count does not contribute to merged maximum",
-										dst["regions"][reg1_name]["get_other"]["resp_max"].asReal(), F64(-23.2892), 20);
+			ensure_equals("dst counts come from src only (flipped)", 3, dst["regions"][region1_handle_str]["get_other"]["resp_count"].asInteger());
+
+			ensure_approximately_equals("dst maximum with count 0 does not contribute to merged maximum (flipped)",
+										dst["regions"][region1_handle_str]["get_other"]["resp_max"].asReal(), F64(0.0), 20);
 		}
 	}
 
-    // resp_count unspecified is taken as 0 for minimum merges
+    // Minimum merges are interesting when one side contributes nothing
 	template<> template<>
-	void tst_viewerassetstats_index_object_t::test<13>()
+	void tst_viewerassetstats_index_object_t::test<12>()
 	{
-		LLSD::String reg1_name = region1.asString();
-		LLSD::String reg2_name = region2.asString();
-
-		LLSD reg1_stats = LLSD::emptyMap();
-		LLSD reg2_stats = LLSD::emptyMap();
-
-		LLSD & tmp_other1 = reg1_stats["get_other"];
-		tmp_other1["enqueued"] = 4;
-		tmp_other1["dequeued"] = 4;
-		tmp_other1["resp_count"] = 7;
-		tmp_other1["resp_max"] = F64(123.2892);
-		tmp_other1["resp_min"] = F64(23.2892);
-		tmp_other1["resp_mean"] = F64(58.28298);
-
-		LLSD & tmp_other2 = reg2_stats["get_other"];
-		tmp_other2["enqueued"] = 8;
-		tmp_other2["dequeued"] = 7;
-		// tmp_other2["resp_count"] = 0;
-		tmp_other2["resp_max"] = F64(0);
-		tmp_other2["resp_min"] = F64(0);
-		tmp_other2["resp_mean"] = F64(0);
-		
+		LLViewerAssetStats s1;
+		LLViewerAssetStats s2;
+
+		s1.setRegion(region1_handle);
+		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 3800000);
+		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 2700000);
+		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 2900000);
+
+		s2.setRegion(region1_handle);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
 		{
-			LLSD src = LLSD::emptyMap();
-			LLSD dst = LLSD::emptyMap();
+			s2.merge(s1);
+			
+			LLSD src = s1.asLLSD();
+			LLSD dst = s2.asLLSD();
 
-			src["regions"][reg1_name] = reg1_stats;
-			src["duration"] = 24;
-			dst["regions"][reg1_name] = reg2_stats;
-			dst["duration"] = 36;
+			// Remove time stamps, they're a problem
+			src.erase("duration");
+			src["regions"][region1_handle_str].erase("duration");
+			dst.erase("duration");
+			dst["regions"][region1_handle_str].erase("duration");
 
-			LLViewerAssetStats::mergeRegionsLLSD(src, dst);
-		
-			ensure_approximately_equals("dst minimum with undefined count does not contribute to merged minimum",
-										dst["regions"][reg1_name]["get_other"]["resp_min"].asReal(), F64(23.2892), 20);
+			ensure_equals("dst counts come from src only", 3, dst["regions"][region1_handle_str]["get_other"]["resp_count"].asInteger());
+
+			ensure_approximately_equals("dst minimum with count 0 does not contribute to merged minimum",
+										dst["regions"][region1_handle_str]["get_other"]["resp_min"].asReal(), F64(2.7), 20);
 		}
 
+		// Other way around
+		s1.setRegion(region1_handle);
+		s2.setRegion(region1_handle);
+		s1.reset();
+		s2.reset();
+
+		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s1.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 3800000);
+		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 2700000);
+		s1.recordGetServiced(LLViewerAssetType::AT_LSL_BYTECODE, true, true, 2900000);
+
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetEnqueued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+		s2.recordGetDequeued(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
+
 		{
-			LLSD src = LLSD::emptyMap();
-			LLSD dst = LLSD::emptyMap();
+			s1.merge(s2);
+			
+			LLSD src = s2.asLLSD();
+			LLSD dst = s1.asLLSD();
 
-			src["regions"][reg1_name] = reg2_stats;
-			src["duration"] = 24;
-			dst["regions"][reg1_name] = reg1_stats;
-			dst["duration"] = 36;
+			// Remove time stamps, they're a problem
+			src.erase("duration");
+			src["regions"][region1_handle_str].erase("duration");
+			dst.erase("duration");
+			dst["regions"][region1_handle_str].erase("duration");
 
-			LLViewerAssetStats::mergeRegionsLLSD(src, dst);
-		
-			ensure_approximately_equals("src minimum with undefined count does not contribute to merged minimum",
-										dst["regions"][reg1_name]["get_other"]["resp_min"].asReal(), F64(23.2892), 20);
+			ensure_equals("dst counts come from src only (flipped)", 3, dst["regions"][region1_handle_str]["get_other"]["resp_count"].asInteger());
+
+			ensure_approximately_equals("dst minimum with count 0 does not contribute to merged minimum (flipped)",
+										dst["regions"][region1_handle_str]["get_other"]["resp_min"].asReal(), F64(2.7), 20);
 		}
 	}
+
 }
-- 
cgit v1.2.3


From 1d686283a467808eda2d7bd8a2c109d4924151f2 Mon Sep 17 00:00:00 2001
From: Vadim ProductEngine <vsavchuk@productengine.com>
Date: Sat, 11 Dec 2010 17:24:39 +0200
Subject: STORM-391 WIP Removed unused methods.

---
 indra/newview/llscreenchannel.cpp | 5 -----
 indra/newview/llscreenchannel.h   | 3 ---
 2 files changed, 8 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp
index 9e0e10d66f..64e75a6cb2 100644
--- a/indra/newview/llscreenchannel.cpp
+++ b/indra/newview/llscreenchannel.cpp
@@ -605,10 +605,6 @@ void LLScreenChannel::showToastsBottom()
 			mHiddenToastsNum++;
 		}
 	}
-	else
-	{
-		closeOverflowToastPanel();
-	}
 }
 
 //--------------------------------------------------------------------------
@@ -731,7 +727,6 @@ void LLNotificationsUI::LLScreenChannel::startToastTimer(LLToast* toast)
 //--------------------------------------------------------------------------
 void LLScreenChannel::hideToastsFromScreen()
 {
-	closeOverflowToastPanel();
 	for(std::vector<ToastElem>::iterator it = mToastList.begin(); it != mToastList.end(); it++)
 		(*it).toast->setVisible(FALSE);
 }
diff --git a/indra/newview/llscreenchannel.h b/indra/newview/llscreenchannel.h
index 023a65d872..c536a21779 100644
--- a/indra/newview/llscreenchannel.h
+++ b/indra/newview/llscreenchannel.h
@@ -81,9 +81,6 @@ public:
 	// show all toasts in a channel
 	virtual void		redrawToasts() {};
 
-	virtual void 		closeOverflowToastPanel() {};
-	virtual void 		hideOverflowToastPanel() {};
-
 	
 	// Channel's behavior-functions
 	// set whether a channel will control hovering inside itself or not
-- 
cgit v1.2.3


From 0d764afb9c0ba5dd3aeed67370f8d5c7d9b7cf45 Mon Sep 17 00:00:00 2001
From: Vadim ProductEngine <vsavchuk@productengine.com>
Date: Sat, 11 Dec 2010 18:02:59 +0200
Subject: STORM-391 FIXED Dismiss toasts that don't fit on screen.

Make sure older toasts don't appear after newer ones fade out.
---
 indra/newview/llscreenchannel.cpp | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp
index 64e75a6cb2..0eeb89792b 100644
--- a/indra/newview/llscreenchannel.cpp
+++ b/indra/newview/llscreenchannel.cpp
@@ -595,14 +595,13 @@ void LLScreenChannel::showToastsBottom()
 		}
 	}
 
+	// Dismiss toasts we don't have space for (STORM-391).
 	if(it != mToastList.rend())
 	{
 		mHiddenToastsNum = 0;
 		for(; it != mToastList.rend(); it++)
 		{
-			(*it).toast->stopTimer();
-			(*it).toast->setVisible(FALSE);
-			mHiddenToastsNum++;
+			(*it).toast->hide();
 		}
 	}
 }
-- 
cgit v1.2.3


From 872e4dcdde979981d35889152dbee827775c4b7c Mon Sep 17 00:00:00 2001
From: Vadim ProductEngine <vsavchuk@productengine.com>
Date: Sat, 11 Dec 2010 18:54:33 +0200
Subject: STORM-766 ADDITIONAL FIX Made day cycle image in the advanced sky
 editor honor floater opacity settings.

---
 indra/newview/skins/default/xui/en/floater_windlight_options.xml | 1 +
 1 file changed, 1 insertion(+)

(limited to 'indra/newview')

diff --git a/indra/newview/skins/default/xui/en/floater_windlight_options.xml b/indra/newview/skins/default/xui/en/floater_windlight_options.xml
index 85a5be369c..249ad95c41 100644
--- a/indra/newview/skins/default/xui/en/floater_windlight_options.xml
+++ b/indra/newview/skins/default/xui/en/floater_windlight_options.xml
@@ -594,6 +594,7 @@
              left_delta="14"
              top_pad="10"
              name="SkyDayCycle"
+             use_draw_context_alpha="false"
              width="148" />
             <slider
              control_name="WLSunAngle"
-- 
cgit v1.2.3


From bb53d27b7ad6e7bb7b1871f103b221703d56e4d2 Mon Sep 17 00:00:00 2001
From: Monty Brandenberg <monty@lindenlab.com>
Date: Sat, 11 Dec 2010 16:16:07 -0500
Subject: ESC-211 ESC-212 Use arrays in payload to grid and compact payload
 First, introduced a compact payload format that allows blocks of metrics to
 be dropped from the viewer->collector payload compressing 1200 bytes of LLSD
 into about 300, give-or-take.  Then converted to using LLSD arrays in the
 payload to enumerate the regions encountered.  This simplifies much data
 handling from the viewer all the way into the final formatter of the metrics
 on the grid.

---
 indra/newview/llappviewer.cpp                   |  2 +-
 indra/newview/lltexturefetch.cpp                |  2 +-
 indra/newview/llviewerassetstats.cpp            | 42 ++++++++++++-------
 indra/newview/llviewerassetstats.h              | 10 ++++-
 indra/newview/tests/llviewerassetstats_test.cpp | 56 ++++++++++++-------------
 5 files changed, 64 insertions(+), 48 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 3640d01642..32bd51d3e2 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -3808,7 +3808,7 @@ void LLAppViewer::idle()
 			// ViewerMetrics FPS piggy-backing on the debug timer.
 			// The 5-second interval is nice for this purpose.  If the object debug
 			// bit moves or is disabled, please give this a suitable home.
-			LLViewerAssetStatsFF::record_fps_main(frame_rate_clamped);
+			LLViewerAssetStatsFF::record_fps_main(gFPSClamped);
 		}
 	}
 
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index e1f9d7bdcc..88905372f6 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -2915,7 +2915,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
 
 	// Merge existing stats into those from main, convert to LLSD
 	main_stats.merge(*gViewerAssetStatsThread1);
-	LLSD merged_llsd = main_stats.asLLSD();
+	LLSD merged_llsd = main_stats.asLLSD(true);
 
 	// Add some additional meta fields to the content
 	merged_llsd["session_id"] = mSessionID;
diff --git a/indra/newview/llviewerassetstats.cpp b/indra/newview/llviewerassetstats.cpp
index 399d62d2fc..5ad7725b3e 100644
--- a/indra/newview/llviewerassetstats.cpp
+++ b/indra/newview/llviewerassetstats.cpp
@@ -33,6 +33,7 @@
 #include "llviewerprecompiledheaders.h"
 
 #include "llviewerassetstats.h"
+#include "llregionhandle.h"
 
 #include "stdtypes.h"
 
@@ -258,7 +259,7 @@ LLViewerAssetStats::recordFPS(F32 fps)
 }
 
 LLSD
-LLViewerAssetStats::asLLSD()
+LLViewerAssetStats::asLLSD(bool compact_output)
 {
 	// Top-level tags
 	static const LLSD::String tags[EVACCount] = 
@@ -290,7 +291,7 @@ LLViewerAssetStats::asLLSD()
 	const duration_t now = LLViewerAssetStatsFF::get_timestamp();
 	mCurRegionStats->accumulateTime(now);
 
-	LLSD regions = LLSD::emptyMap();
+	LLSD regions = LLSD::emptyArray();
 	for (PerRegionContainer::iterator it = mRegionStats.begin();
 		 mRegionStats.end() != it;
 		 ++it)
@@ -307,16 +308,25 @@ LLViewerAssetStats::asLLSD()
 		
 		for (int i = 0; i < LL_ARRAY_SIZE(tags); ++i)
 		{
-			LLSD & slot = reg_stat[tags[i]];
-			slot = LLSD::emptyMap();
-			slot[enq_tag] = LLSD(S32(stats.mRequests[i].mEnqueued.getCount()));
-			slot[deq_tag] = LLSD(S32(stats.mRequests[i].mDequeued.getCount()));
-			slot[rcnt_tag] = LLSD(S32(stats.mRequests[i].mResponse.getCount()));
-			slot[rmin_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMin() * 1.0e-6));
-			slot[rmax_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMax() * 1.0e-6));
-			slot[rmean_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMean() * 1.0e-6));
+			PerRegionStats::prs_group & group(stats.mRequests[i]);
+			
+			if ((! compact_output) ||
+				group.mEnqueued.getCount() ||
+				group.mDequeued.getCount() ||
+				group.mResponse.getCount())
+			{
+				LLSD & slot = reg_stat[tags[i]];
+				slot = LLSD::emptyMap();
+				slot[enq_tag] = LLSD(S32(stats.mRequests[i].mEnqueued.getCount()));
+				slot[deq_tag] = LLSD(S32(stats.mRequests[i].mDequeued.getCount()));
+				slot[rcnt_tag] = LLSD(S32(stats.mRequests[i].mResponse.getCount()));
+				slot[rmin_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMin() * 1.0e-6));
+				slot[rmax_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMax() * 1.0e-6));
+				slot[rmean_tag] = LLSD(F64(stats.mRequests[i].mResponse.getMean() * 1.0e-6));
+			}
 		}
 
+		if ((! compact_output) || stats.mFPS.getCount())
 		{
 			LLSD & slot = reg_stat["fps"];
 			slot = LLSD::emptyMap();
@@ -326,12 +336,12 @@ LLViewerAssetStats::asLLSD()
 			slot[mean_tag] = LLSD(F64(stats.mFPS.getMean()));
 		}
 
-		reg_stat["duration"] = LLSD::Real(stats.mTotalTime * 1.0e-6);
-		std::stringstream reg_handle;
-		reg_handle.width(16);
-		reg_handle.fill('0');
-		reg_handle << std::hex << it->first;
-		regions[reg_handle.str()] = reg_stat;
+		U32 grid_x(0), grid_y(0);
+		grid_from_region_handle(it->first, &grid_x, &grid_y);
+		reg_stat["grid_x"] = LLSD::Integer(grid_x);
+		reg_stat["grid_y"] = LLSD::Integer(grid_y);
+		reg_stat["duration"] = LLSD::Real(stats.mTotalTime * 1.0e-6);		
+		regions.append(reg_stat);
 	}
 
 	LLSD ret = LLSD::emptyMap();
diff --git a/indra/newview/llviewerassetstats.h b/indra/newview/llviewerassetstats.h
index af6bf5b695..905ceefad5 100644
--- a/indra/newview/llviewerassetstats.h
+++ b/indra/newview/llviewerassetstats.h
@@ -155,7 +155,7 @@ public:
 		duration_t			mStartTimestamp;
 		LLSimpleStatMMM<>	mFPS;
 		
-		struct
+		struct prs_group
 		{
 			LLSimpleStatCounter			mEnqueued;
 			LLSimpleStatCounter			mDequeued;
@@ -232,7 +232,13 @@ public:
 	//     }
 	//   }
 	// }
-	LLSD asLLSD();
+	//
+	// @param	compact_output		If true, omits from conversion any mmm_block
+	//								or stats_block that would contain all zero data.
+	//								Useful for transmission when the receiver knows
+	//								what is expected and will assume zero for missing
+	//								blocks.
+	LLSD asLLSD(bool compact_output);
 
 protected:
 	typedef std::map<region_handle_t, LLPointer<PerRegionStats> > PerRegionContainer;
diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp
index 9c54266017..40a7103dba 100644
--- a/indra/newview/tests/llviewerassetstats_test.cpp
+++ b/indra/newview/tests/llviewerassetstats_test.cpp
@@ -155,7 +155,7 @@ namespace tut
 
 		ensure("Global gViewerAssetStatsMain should still be NULL", (NULL == gViewerAssetStatsMain));
 
-		LLSD sd_full = it->asLLSD();
+		LLSD sd_full = it->asLLSD(false);
 
 		// Default (NULL) region ID doesn't produce LLSD results so should
 		// get an empty map back from output
@@ -163,7 +163,7 @@ namespace tut
 
 		// Once the region is set, we will get a response even with no data collection
 		it->setRegion(region1_handle);
-		sd_full = it->asLLSD();
+		sd_full = it->asLLSD(false);
 		ensure("Correct single-key LLSD map root", is_double_key_map(sd_full, "duration", "regions"));
 		ensure("Correct single-key LLSD map regions", is_single_key_map(sd_full["regions"], region1_handle_str));
 		
@@ -204,7 +204,7 @@ namespace tut
 		LLViewerAssetStats * it = new LLViewerAssetStats();
 		it->setRegion(region1_handle);
 		
-		LLSD sd = it->asLLSD();
+		LLSD sd = it->asLLSD(false);
 		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
 		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1_handle_str));
 		sd = sd[region1_handle_str];
@@ -229,7 +229,7 @@ namespace tut
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false);
 		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false);
 
-		LLSD sd = gViewerAssetStatsMain->asLLSD();
+		LLSD sd = gViewerAssetStatsMain->asLLSD(false);
 		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
 		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1_handle_str));
 		sd = sd["regions"][region1_handle_str];
@@ -244,7 +244,7 @@ namespace tut
 		// Reset and check zeros...
 		// Reset leaves current region in place
 		gViewerAssetStatsMain->reset();
-		sd = gViewerAssetStatsMain->asLLSD()["regions"][region1_handle_str];
+		sd = gViewerAssetStatsMain->asLLSD(false)["regions"][region1_handle_str];
 		
 		delete gViewerAssetStatsMain;
 		gViewerAssetStatsMain = NULL;
@@ -267,9 +267,9 @@ namespace tut
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_BODYPART, false, false);
 		LLViewerAssetStatsFF::record_dequeue_main(LLViewerAssetType::AT_BODYPART, false, false);
 
-		LLSD sd = gViewerAssetStatsThread1->asLLSD();
+		LLSD sd = gViewerAssetStatsThread1->asLLSD(false);
 		ensure("Other collector is empty", is_no_stats_map(sd));
-		sd = gViewerAssetStatsMain->asLLSD();
+		sd = gViewerAssetStatsMain->asLLSD(false);
 		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
 		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1_handle_str));
 		sd = sd["regions"][region1_handle_str];
@@ -284,7 +284,7 @@ namespace tut
 		// Reset and check zeros...
 		// Reset leaves current region in place
 		gViewerAssetStatsMain->reset();
-		sd = gViewerAssetStatsMain->asLLSD()["regions"][region1_handle_str];
+		sd = gViewerAssetStatsMain->asLLSD(false)["regions"][region1_handle_str];
 		
 		delete gViewerAssetStatsMain;
 		gViewerAssetStatsMain = NULL;
@@ -316,7 +316,7 @@ namespace tut
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
 
-		LLSD sd = gViewerAssetStatsMain->asLLSD();
+		LLSD sd = gViewerAssetStatsMain->asLLSD(false);
 
 		// std::cout << sd << std::endl;
 		
@@ -340,7 +340,7 @@ namespace tut
 		// Reset and check zeros...
 		// Reset leaves current region in place
 		gViewerAssetStatsMain->reset();
-		sd = gViewerAssetStatsMain->asLLSD();
+		sd = gViewerAssetStatsMain->asLLSD(false);
 		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
 		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region2_handle_str));
 		sd2 = sd["regions"][region2_handle_str];
@@ -388,7 +388,7 @@ namespace tut
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_GESTURE, false, false);
 
-		LLSD sd = gViewerAssetStatsMain->asLLSD();
+		LLSD sd = gViewerAssetStatsMain->asLLSD(false);
 
 		ensure("Correct double-key LLSD map root", is_double_key_map(sd, "duration", "regions"));
 		ensure("Correct double-key LLSD map regions", is_double_key_map(sd["regions"], region1_handle_str, region2_handle_str));
@@ -410,7 +410,7 @@ namespace tut
 		// Reset and check zeros...
 		// Reset leaves current region in place
 		gViewerAssetStatsMain->reset();
-		sd = gViewerAssetStatsMain->asLLSD();
+		sd = gViewerAssetStatsMain->asLLSD(false);
 		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "duration", "regions"));
 		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region2_handle_str));
 		sd2 = sd["regions"][region2_handle_str];
@@ -453,9 +453,9 @@ namespace tut
 
 		LLViewerAssetStatsFF::record_enqueue_main(LLViewerAssetType::AT_LSL_BYTECODE, true, true);
 
-		LLSD sd = gViewerAssetStatsThread1->asLLSD();
+		LLSD sd = gViewerAssetStatsThread1->asLLSD(false);
 		ensure("Other collector is empty", is_no_stats_map(sd));
-		sd = gViewerAssetStatsMain->asLLSD();
+		sd = gViewerAssetStatsMain->asLLSD(false);
 		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
 		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1_handle_str));
 		sd = sd["regions"][region1_handle_str];
@@ -473,7 +473,7 @@ namespace tut
 		// Reset and check zeros...
 		// Reset leaves current region in place
 		gViewerAssetStatsMain->reset();
-		sd = gViewerAssetStatsMain->asLLSD()["regions"][region1_handle_str];
+		sd = gViewerAssetStatsMain->asLLSD(false)["regions"][region1_handle_str];
 		
 		delete gViewerAssetStatsMain;
 		gViewerAssetStatsMain = NULL;
@@ -507,7 +507,7 @@ namespace tut
 
 		s2.merge(s1);
 
-		LLSD s2_llsd = s2.asLLSD();
+		LLSD s2_llsd = s2.asLLSD(false);
 		
 		ensure_equals("count after merge", 8, s2_llsd["regions"][region1_handle_str]["get_texture_temp_http"]["resp_count"].asInteger());
 		ensure_approximately_equals("min after merge", 2.0, s2_llsd["regions"][region1_handle_str]["get_texture_temp_http"]["resp_min"].asReal(), 22);
@@ -562,8 +562,8 @@ namespace tut
 		{
 			s2.merge(s1);
 			
-			LLSD src = s1.asLLSD();
-			LLSD dst = s2.asLLSD();
+			LLSD src = s1.asLLSD(false);
+			LLSD dst = s2.asLLSD(false);
 
 			// Remove time stamps, they're a problem
 			src.erase("duration");
@@ -621,8 +621,8 @@ namespace tut
 		{
 			s2.merge(s1);
 			
-			LLSD src = s1.asLLSD();
-			LLSD dst = s2.asLLSD();
+			LLSD src = s1.asLLSD(false);
+			LLSD dst = s2.asLLSD(false);
 
 			// Remove time stamps, they're a problem
 			src.erase("duration");
@@ -689,8 +689,8 @@ namespace tut
 		{
 			s2.merge(s1);
 			
-			LLSD src = s1.asLLSD();
-			LLSD dst = s2.asLLSD();
+			LLSD src = s1.asLLSD(false);
+			LLSD dst = s2.asLLSD(false);
 
 			// Remove time stamps, they're a problem
 			src.erase("duration");
@@ -745,8 +745,8 @@ namespace tut
 		{
 			s1.merge(s2);
 			
-			LLSD src = s2.asLLSD();
-			LLSD dst = s1.asLLSD();
+			LLSD src = s2.asLLSD(false);
+			LLSD dst = s1.asLLSD(false);
 
 			// Remove time stamps, they're a problem
 			src.erase("duration");
@@ -804,8 +804,8 @@ namespace tut
 		{
 			s2.merge(s1);
 			
-			LLSD src = s1.asLLSD();
-			LLSD dst = s2.asLLSD();
+			LLSD src = s1.asLLSD(false);
+			LLSD dst = s2.asLLSD(false);
 
 			// Remove time stamps, they're a problem
 			src.erase("duration");
@@ -859,8 +859,8 @@ namespace tut
 		{
 			s1.merge(s2);
 			
-			LLSD src = s2.asLLSD();
-			LLSD dst = s1.asLLSD();
+			LLSD src = s2.asLLSD(false);
+			LLSD dst = s1.asLLSD(false);
 
 			// Remove time stamps, they're a problem
 			src.erase("duration");
-- 
cgit v1.2.3


From e0e223c196972e91da80b852921fe3ff627f8a68 Mon Sep 17 00:00:00 2001
From: Monty Brandenberg <monty@lindenlab.com>
Date: Sat, 11 Dec 2010 14:37:00 -0800
Subject: Update unit tests to reflect the new array-of-regions style of LLSD
 serialization for viewer metrics.

---
 indra/newview/tests/llviewerassetstats_test.cpp | 268 +++++++++++++++++-------
 1 file changed, 190 insertions(+), 78 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp
index 40a7103dba..1bb4fb7c0c 100644
--- a/indra/newview/tests/llviewerassetstats_test.cpp
+++ b/indra/newview/tests/llviewerassetstats_test.cpp
@@ -40,6 +40,7 @@
 #include "../llviewerassetstats.h"
 #include "lluuid.h"
 #include "llsdutil.h"
+#include "llregionhandle.h"
 
 static const char * all_keys[] = 
 {
@@ -92,10 +93,10 @@ static const char * mmm_sub_keys[] =
 
 static const LLUUID region1("4e2d81a3-6263-6ffe-ad5c-8ce04bee07e8");
 static const LLUUID region2("68762cc8-b68b-4e45-854b-e830734f2d4a");
-static const U64 region1_handle(0x00000401000003f7ULL);
-static const U64 region2_handle(0x000003f800000420ULL);
-static const std::string region1_handle_str("00000401000003f7");
-static const std::string region2_handle_str("000003f800000420");
+static const U64 region1_handle(0x0000040000003f00ULL);
+static const U64 region2_handle(0x0000030000004200ULL);
+static const std::string region1_handle_str("0000040000003f00");
+static const std::string region2_handle_str("0000030000004200");
 
 #if 0
 static bool
@@ -103,13 +104,13 @@ is_empty_map(const LLSD & sd)
 {
 	return sd.isMap() && 0 == sd.size();
 }
-#endif
 
 static bool
 is_single_key_map(const LLSD & sd, const std::string & key)
 {
 	return sd.isMap() && 1 == sd.size() && sd.has(key);
 }
+#endif
 
 static bool
 is_double_key_map(const LLSD & sd, const std::string & key1, const std::string & key2)
@@ -123,6 +124,73 @@ is_no_stats_map(const LLSD & sd)
 	return is_double_key_map(sd, "duration", "regions");
 }
 
+static bool
+is_single_slot_array(const LLSD & sd, U64 region_handle)
+{
+	U32 grid_x(0), grid_y(0);
+	grid_from_region_handle(region_handle, &grid_x, &grid_y);
+	
+	return (sd.isArray() &&
+			1 == sd.size() &&
+			sd[0].has("grid_x") &&
+			sd[0].has("grid_y") &&
+			sd[0]["grid_x"].isInteger() &&
+			sd[0]["grid_y"].isInteger() &&
+			grid_x == sd[0]["grid_x"].asInteger() &&
+			grid_y == sd[0]["grid_y"].asInteger());
+}
+
+static bool
+is_double_slot_array(const LLSD & sd, U64 region_handle1, U64 region_handle2)
+{
+	U32 grid_x1(0), grid_y1(0);
+	U32 grid_x2(0), grid_y2(0);
+	grid_from_region_handle(region_handle1, &grid_x1, &grid_y1);
+	grid_from_region_handle(region_handle2, &grid_x2, &grid_y2);
+	
+	return (sd.isArray() &&
+			2 == sd.size() &&
+			sd[0].has("grid_x") &&
+			sd[0].has("grid_y") &&
+			sd[0]["grid_x"].isInteger() &&
+			sd[0]["grid_y"].isInteger() &&
+			sd[1].has("grid_x") &&
+			sd[1].has("grid_y") &&
+			sd[1]["grid_x"].isInteger() &&
+			sd[1]["grid_y"].isInteger() &&
+			((grid_x1 == sd[0]["grid_x"].asInteger() &&
+			  grid_y1 == sd[0]["grid_y"].asInteger() &&
+			  grid_x2 == sd[1]["grid_x"].asInteger() &&
+			  grid_y2 == sd[1]["grid_y"].asInteger()) ||
+			 (grid_x1 == sd[1]["grid_x"].asInteger() &&
+			  grid_y1 == sd[1]["grid_y"].asInteger() &&
+			  grid_x2 == sd[0]["grid_x"].asInteger() &&
+			  grid_y2 == sd[0]["grid_y"].asInteger())));
+}
+
+static LLSD
+get_region(const LLSD & sd, U64 region_handle1)
+{
+	U32 grid_x(0), grid_y(0);
+	grid_from_region_handle(region_handle1, &grid_x, &grid_y);
+
+	for (LLSD::array_const_iterator it(sd["regions"].beginArray());
+		 sd["regions"].endArray() != it;
+		 ++it)
+	{
+		if ((*it).has("grid_x") &&
+			(*it).has("grid_y") &&
+			(*it)["grid_x"].isInteger() &&
+			(*it)["grid_y"].isInteger() &&
+			(*it)["grid_x"].asInteger() == grid_x &&
+			(*it)["grid_y"].asInteger() == grid_y)
+		{
+			return *it;
+		}
+	}
+	return LLSD();
+}
+
 namespace tut
 {
 	struct tst_viewerassetstats_index
@@ -165,9 +233,9 @@ namespace tut
 		it->setRegion(region1_handle);
 		sd_full = it->asLLSD(false);
 		ensure("Correct single-key LLSD map root", is_double_key_map(sd_full, "duration", "regions"));
-		ensure("Correct single-key LLSD map regions", is_single_key_map(sd_full["regions"], region1_handle_str));
+		ensure("Correct single-slot LLSD array regions", is_single_slot_array(sd_full["regions"], region1_handle));
 		
-		LLSD sd = sd_full["regions"][region1_handle_str];
+		LLSD sd = sd_full["regions"][0];
 
 		delete it;
 			
@@ -206,8 +274,8 @@ namespace tut
 		
 		LLSD sd = it->asLLSD(false);
 		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
-		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1_handle_str));
-		sd = sd[region1_handle_str];
+		ensure("Correct single-slot LLSD array regions", is_single_slot_array(sd["regions"], region1_handle));
+		sd = sd[0];
 		
 		delete it;
 
@@ -231,8 +299,8 @@ namespace tut
 
 		LLSD sd = gViewerAssetStatsMain->asLLSD(false);
 		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
-		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1_handle_str));
-		sd = sd["regions"][region1_handle_str];
+		ensure("Correct single-slot LLSD array regions", is_single_slot_array(sd["regions"], region1_handle));
+		sd = sd["regions"][0];
 		
 		// Check a few points on the tree for content
 		ensure("sd[get_texture_non_temp_udp][enqueued] is 1", (1 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger()));
@@ -271,8 +339,8 @@ namespace tut
 		ensure("Other collector is empty", is_no_stats_map(sd));
 		sd = gViewerAssetStatsMain->asLLSD(false);
 		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
-		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1_handle_str));
-		sd = sd["regions"][region1_handle_str];
+		ensure("Correct single-slot LLSD array regions", is_single_slot_array(sd["regions"], region1_handle));
+		sd = sd["regions"][0];
 		
 		// Check a few points on the tree for content
 		ensure("sd[get_texture_non_temp_udp][enqueued] is 1", (1 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger()));
@@ -284,7 +352,7 @@ namespace tut
 		// Reset and check zeros...
 		// Reset leaves current region in place
 		gViewerAssetStatsMain->reset();
-		sd = gViewerAssetStatsMain->asLLSD(false)["regions"][region1_handle_str];
+		sd = gViewerAssetStatsMain->asLLSD(false)["regions"][0];
 		
 		delete gViewerAssetStatsMain;
 		gViewerAssetStatsMain = NULL;
@@ -321,16 +389,18 @@ namespace tut
 		// std::cout << sd << std::endl;
 		
 		ensure("Correct double-key LLSD map root", is_double_key_map(sd, "duration", "regions"));
-		ensure("Correct double-key LLSD map regions", is_double_key_map(sd["regions"], region1_handle_str, region2_handle_str));
-		LLSD sd1 = sd["regions"][region1_handle_str];
-		LLSD sd2 = sd["regions"][region2_handle_str];
+		ensure("Correct double-slot LLSD array regions", is_double_slot_array(sd["regions"], region1_handle, region2_handle));
+		LLSD sd1 = get_region(sd, region1_handle);
+		LLSD sd2 = get_region(sd, region2_handle);
+		ensure("Region1 is present in results", sd1.isMap());
+		ensure("Region2 is present in results", sd2.isMap());
 		
 		// Check a few points on the tree for content
-		ensure("sd1[get_texture_non_temp_udp][enqueued] is 1", (1 == sd1["get_texture_non_temp_udp"]["enqueued"].asInteger()));
-		ensure("sd1[get_texture_temp_udp][enqueued] is 0", (0 == sd1["get_texture_temp_udp"]["enqueued"].asInteger()));
-		ensure("sd1[get_texture_non_temp_http][enqueued] is 0", (0 == sd1["get_texture_non_temp_http"]["enqueued"].asInteger()));
-		ensure("sd1[get_texture_temp_http][enqueued] is 0", (0 == sd1["get_texture_temp_http"]["enqueued"].asInteger()));
-		ensure("sd1[get_gesture_udp][dequeued] is 0", (0 == sd1["get_gesture_udp"]["dequeued"].asInteger()));
+		ensure_equals("sd1[get_texture_non_temp_udp][enqueued] is 1", sd1["get_texture_non_temp_udp"]["enqueued"].asInteger(), 1);
+		ensure_equals("sd1[get_texture_temp_udp][enqueued] is 0", sd1["get_texture_temp_udp"]["enqueued"].asInteger(), 0);
+		ensure_equals("sd1[get_texture_non_temp_http][enqueued] is 0", sd1["get_texture_non_temp_http"]["enqueued"].asInteger(), 0);
+		ensure_equals("sd1[get_texture_temp_http][enqueued] is 0", sd1["get_texture_temp_http"]["enqueued"].asInteger(), 0);
+		ensure_equals("sd1[get_gesture_udp][dequeued] is 0", sd1["get_gesture_udp"]["dequeued"].asInteger(), 0);
 
 		// Check a few points on the tree for content
 		ensure("sd2[get_gesture_udp][enqueued] is 4", (4 == sd2["get_gesture_udp"]["enqueued"].asInteger()));
@@ -342,8 +412,8 @@ namespace tut
 		gViewerAssetStatsMain->reset();
 		sd = gViewerAssetStatsMain->asLLSD(false);
 		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
-		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region2_handle_str));
-		sd2 = sd["regions"][region2_handle_str];
+		ensure("Correct single-slot LLSD array regions (p2)", is_single_slot_array(sd["regions"], region2_handle));
+		sd2 = sd["regions"][0];
 		
 		delete gViewerAssetStatsMain;
 		gViewerAssetStatsMain = NULL;
@@ -391,9 +461,11 @@ namespace tut
 		LLSD sd = gViewerAssetStatsMain->asLLSD(false);
 
 		ensure("Correct double-key LLSD map root", is_double_key_map(sd, "duration", "regions"));
-		ensure("Correct double-key LLSD map regions", is_double_key_map(sd["regions"], region1_handle_str, region2_handle_str));
-		LLSD sd1 = sd["regions"][region1_handle_str];
-		LLSD sd2 = sd["regions"][region2_handle_str];
+		ensure("Correct double-slot LLSD array regions", is_double_slot_array(sd["regions"], region1_handle, region2_handle));
+		LLSD sd1 = get_region(sd, region1_handle);
+		LLSD sd2 = get_region(sd, region2_handle);
+		ensure("Region1 is present in results", sd1.isMap());
+		ensure("Region2 is present in results", sd2.isMap());
 		
 		// Check a few points on the tree for content
 		ensure("sd1[get_texture_non_temp_udp][enqueued] is 1", (1 == sd1["get_texture_non_temp_udp"]["enqueued"].asInteger()));
@@ -412,14 +484,15 @@ namespace tut
 		gViewerAssetStatsMain->reset();
 		sd = gViewerAssetStatsMain->asLLSD(false);
 		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "duration", "regions"));
-		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region2_handle_str));
-		sd2 = sd["regions"][region2_handle_str];
+		ensure("Correct single-slot LLSD array regions (p2)", is_single_slot_array(sd["regions"], region2_handle));
+		sd2 = get_region(sd, region2_handle);
+		ensure("Region2 is present in results", sd2.isMap());
 		
 		delete gViewerAssetStatsMain;
 		gViewerAssetStatsMain = NULL;
 
-		ensure("sd2[get_texture_non_temp_udp][enqueued] is reset", (0 == sd2["get_texture_non_temp_udp"]["enqueued"].asInteger()));
-		ensure("sd2[get_gesture_udp][enqueued] is reset", (0 == sd2["get_gesture_udp"]["enqueued"].asInteger()));
+		ensure_equals("sd2[get_texture_non_temp_udp][enqueued] is reset", sd2["get_texture_non_temp_udp"]["enqueued"].asInteger(), 0);
+		ensure_equals("sd2[get_gesture_udp][enqueued] is reset", sd2["get_gesture_udp"]["enqueued"].asInteger(), 0);
 	}
 
 	// Non-texture assets ignore transport and persistence flags
@@ -457,8 +530,9 @@ namespace tut
 		ensure("Other collector is empty", is_no_stats_map(sd));
 		sd = gViewerAssetStatsMain->asLLSD(false);
 		ensure("Correct single-key LLSD map root", is_double_key_map(sd, "regions", "duration"));
-		ensure("Correct single-key LLSD map regions", is_single_key_map(sd["regions"], region1_handle_str));
-		sd = sd["regions"][region1_handle_str];
+		ensure("Correct single-slot LLSD array regions", is_single_slot_array(sd["regions"], region1_handle));
+		sd = get_region(sd, region1_handle);
+		ensure("Region1 is present in results", sd.isMap());
 		
 		// Check a few points on the tree for content
 		ensure("sd[get_gesture_udp][enqueued] is 0", (0 == sd["get_gesture_udp"]["enqueued"].asInteger()));
@@ -473,15 +547,16 @@ namespace tut
 		// Reset and check zeros...
 		// Reset leaves current region in place
 		gViewerAssetStatsMain->reset();
-		sd = gViewerAssetStatsMain->asLLSD(false)["regions"][region1_handle_str];
+		sd = get_region(gViewerAssetStatsMain->asLLSD(false), region1_handle);
+		ensure("Region1 is present in results", sd.isMap());
 		
 		delete gViewerAssetStatsMain;
 		gViewerAssetStatsMain = NULL;
 		delete gViewerAssetStatsThread1;
 		gViewerAssetStatsThread1 = NULL;
 
-		ensure("sd[get_texture_non_temp_udp][enqueued] is reset", (0 == sd["get_texture_non_temp_udp"]["enqueued"].asInteger()));
-		ensure("sd[get_gesture_udp][dequeued] is reset", (0 == sd["get_gesture_udp"]["dequeued"].asInteger()));
+		ensure_equals("sd[get_texture_non_temp_udp][enqueued] is reset", sd["get_texture_non_temp_udp"]["enqueued"].asInteger(), 0);
+		ensure_equals("sd[get_gesture_udp][dequeued] is reset", sd["get_gesture_udp"]["dequeued"].asInteger(), 0);
 	}
 
 
@@ -507,13 +582,13 @@ namespace tut
 
 		s2.merge(s1);
 
-		LLSD s2_llsd = s2.asLLSD(false);
+		LLSD s2_llsd = get_region(s2.asLLSD(false), region1_handle);
+		ensure("Region1 is present in results", s2_llsd.isMap());
 		
-		ensure_equals("count after merge", 8, s2_llsd["regions"][region1_handle_str]["get_texture_temp_http"]["resp_count"].asInteger());
-		ensure_approximately_equals("min after merge", 2.0, s2_llsd["regions"][region1_handle_str]["get_texture_temp_http"]["resp_min"].asReal(), 22);
-		ensure_approximately_equals("max after merge", 9.0, s2_llsd["regions"][region1_handle_str]["get_texture_temp_http"]["resp_max"].asReal(), 22);
-		ensure_approximately_equals("max after merge", 5.5, s2_llsd["regions"][region1_handle_str]["get_texture_temp_http"]["resp_mean"].asReal(), 22);
-
+		ensure_equals("count after merge", s2_llsd["get_texture_temp_http"]["resp_count"].asInteger(), 8);
+		ensure_approximately_equals("min after merge", s2_llsd["get_texture_temp_http"]["resp_min"].asReal(), 2.0, 22);
+		ensure_approximately_equals("max after merge", s2_llsd["get_texture_temp_http"]["resp_max"].asReal(), 9.0, 22);
+		ensure_approximately_equals("max after merge", s2_llsd["get_texture_temp_http"]["resp_mean"].asReal(), 5.5, 22);
 	}
 
 	// LLViewerAssetStats::merge() basic functions work without corrupting source data
@@ -565,17 +640,22 @@ namespace tut
 			LLSD src = s1.asLLSD(false);
 			LLSD dst = s2.asLLSD(false);
 
+			ensure_equals("merge src has single region", src["regions"].size(), 1);
+			ensure_equals("merge dst has dual regions", dst["regions"].size(), 2);
+			
 			// Remove time stamps, they're a problem
 			src.erase("duration");
-			src["regions"][region1_handle_str].erase("duration");
+			src["regions"][0].erase("duration");
 			dst.erase("duration");
-			dst["regions"][region1_handle_str].erase("duration");
-			dst["regions"][region2_handle_str].erase("duration");
+			dst["regions"][0].erase("duration");
+			dst["regions"][1].erase("duration");
 
-			ensure_equals("merge src has single region", 1, src["regions"].size());
-			ensure_equals("merge dst has dual regions", 2, dst["regions"].size());
-			ensure("result from src is in dst", llsd_equals(src["regions"][region1_handle_str],
-															dst["regions"][region1_handle_str]));
+			LLSD s1_llsd = get_region(src, region1_handle);
+			ensure("Region1 is present in src", s1_llsd.isMap());
+			LLSD s2_llsd = get_region(dst, region1_handle);
+			ensure("Region1 is present in dst", s2_llsd.isMap());
+
+			ensure("result from src is in dst", llsd_equals(s1_llsd, s2_llsd));
 		}
 
 		s1.setRegion(region1_handle);
@@ -624,23 +704,31 @@ namespace tut
 			LLSD src = s1.asLLSD(false);
 			LLSD dst = s2.asLLSD(false);
 
+			ensure_equals("merge src has single region (p2)", src["regions"].size(), 1);
+			ensure_equals("merge dst has single region (p2)", dst["regions"].size(), 1);
+
 			// Remove time stamps, they're a problem
 			src.erase("duration");
-			src["regions"][region1_handle_str].erase("duration");
+			src["regions"][0].erase("duration");
 			dst.erase("duration");
-			dst["regions"][region1_handle_str].erase("duration");
-
-			ensure_equals("src counts okay (enq)", 4, src["regions"][region1_handle_str]["get_other"]["enqueued"].asInteger());
-			ensure_equals("src counts okay (deq)", 4, src["regions"][region1_handle_str]["get_other"]["dequeued"].asInteger());
-			ensure_equals("src resp counts okay", 2, src["regions"][region1_handle_str]["get_other"]["resp_count"].asInteger());
-			ensure_approximately_equals("src respmin okay", 0.2829, src["regions"][region1_handle_str]["get_other"]["resp_min"].asReal(), 20);
-			ensure_approximately_equals("src respmax okay", 23.2892, src["regions"][region1_handle_str]["get_other"]["resp_max"].asReal(), 20);
+			dst["regions"][0].erase("duration");
+			
+			LLSD s1_llsd = get_region(src, region1_handle);
+			ensure("Region1 is present in src", s1_llsd.isMap());
+			LLSD s2_llsd = get_region(dst, region1_handle);
+			ensure("Region1 is present in dst", s2_llsd.isMap());
+
+			ensure_equals("src counts okay (enq)", s1_llsd["get_other"]["enqueued"].asInteger(), 4);
+			ensure_equals("src counts okay (deq)", s1_llsd["get_other"]["dequeued"].asInteger(), 4);
+			ensure_equals("src resp counts okay", s1_llsd["get_other"]["resp_count"].asInteger(), 2);
+			ensure_approximately_equals("src respmin okay", s1_llsd["get_other"]["resp_min"].asReal(), 0.2829, 20);
+			ensure_approximately_equals("src respmax okay", s1_llsd["get_other"]["resp_max"].asReal(), 23.2892, 20);
 			
-			ensure_equals("dst counts okay (enq)", 12, dst["regions"][region1_handle_str]["get_other"]["enqueued"].asInteger());
-			ensure_equals("src counts okay (deq)", 11, dst["regions"][region1_handle_str]["get_other"]["dequeued"].asInteger());
-			ensure_equals("dst resp counts okay", 4, dst["regions"][region1_handle_str]["get_other"]["resp_count"].asInteger());
-			ensure_approximately_equals("dst respmin okay", 0.010, dst["regions"][region1_handle_str]["get_other"]["resp_min"].asReal(), 20);
-			ensure_approximately_equals("dst respmax okay", 23.2892, dst["regions"][region1_handle_str]["get_other"]["resp_max"].asReal(), 20);
+			ensure_equals("dst counts okay (enq)", s2_llsd["get_other"]["enqueued"].asInteger(), 12);
+			ensure_equals("src counts okay (deq)", s2_llsd["get_other"]["dequeued"].asInteger(), 11);
+			ensure_equals("dst resp counts okay", s2_llsd["get_other"]["resp_count"].asInteger(), 4);
+			ensure_approximately_equals("dst respmin okay", s2_llsd["get_other"]["resp_min"].asReal(), 0.010, 20);
+			ensure_approximately_equals("dst respmax okay", s2_llsd["get_other"]["resp_max"].asReal(), 23.2892, 20);
 		}
 	}
 
@@ -692,16 +780,22 @@ namespace tut
 			LLSD src = s1.asLLSD(false);
 			LLSD dst = s2.asLLSD(false);
 
+			ensure_equals("merge src has single region", src["regions"].size(), 1);
+			ensure_equals("merge dst has single region", dst["regions"].size(), 1);
+			
 			// Remove time stamps, they're a problem
 			src.erase("duration");
-			src["regions"][region1_handle_str].erase("duration");
+			src["regions"][0].erase("duration");
 			dst.erase("duration");
-			dst["regions"][region1_handle_str].erase("duration");
+			dst["regions"][0].erase("duration");
 
-			ensure_equals("dst counts come from src only", 3, dst["regions"][region1_handle_str]["get_other"]["resp_count"].asInteger());
+			LLSD s2_llsd = get_region(dst, region1_handle);
+			ensure("Region1 is present in dst", s2_llsd.isMap());
+			
+			ensure_equals("dst counts come from src only", s2_llsd["get_other"]["resp_count"].asInteger(), 3);
 
 			ensure_approximately_equals("dst maximum with count 0 does not contribute to merged maximum",
-										dst["regions"][region1_handle_str]["get_other"]["resp_max"].asReal(), F64(0.0), 20);
+										s2_llsd["get_other"]["resp_max"].asReal(), F64(0.0), 20);
 		}
 
 		// Other way around
@@ -748,16 +842,22 @@ namespace tut
 			LLSD src = s2.asLLSD(false);
 			LLSD dst = s1.asLLSD(false);
 
+			ensure_equals("merge src has single region", src["regions"].size(), 1);
+			ensure_equals("merge dst has single region", dst["regions"].size(), 1);
+			
 			// Remove time stamps, they're a problem
 			src.erase("duration");
-			src["regions"][region1_handle_str].erase("duration");
+			src["regions"][0].erase("duration");
 			dst.erase("duration");
-			dst["regions"][region1_handle_str].erase("duration");
+			dst["regions"][0].erase("duration");
 
-			ensure_equals("dst counts come from src only (flipped)", 3, dst["regions"][region1_handle_str]["get_other"]["resp_count"].asInteger());
+			LLSD s2_llsd = get_region(dst, region1_handle);
+			ensure("Region1 is present in dst", s2_llsd.isMap());
+
+			ensure_equals("dst counts come from src only (flipped)", s2_llsd["get_other"]["resp_count"].asInteger(), 3);
 
 			ensure_approximately_equals("dst maximum with count 0 does not contribute to merged maximum (flipped)",
-										dst["regions"][region1_handle_str]["get_other"]["resp_max"].asReal(), F64(0.0), 20);
+										s2_llsd["get_other"]["resp_max"].asReal(), F64(0.0), 20);
 		}
 	}
 
@@ -807,16 +907,22 @@ namespace tut
 			LLSD src = s1.asLLSD(false);
 			LLSD dst = s2.asLLSD(false);
 
+			ensure_equals("merge src has single region", src["regions"].size(), 1);
+			ensure_equals("merge dst has single region", dst["regions"].size(), 1);
+			
 			// Remove time stamps, they're a problem
 			src.erase("duration");
-			src["regions"][region1_handle_str].erase("duration");
+			src["regions"][0].erase("duration");
 			dst.erase("duration");
-			dst["regions"][region1_handle_str].erase("duration");
+			dst["regions"][0].erase("duration");
+
+			LLSD s2_llsd = get_region(dst, region1_handle);
+			ensure("Region1 is present in dst", s2_llsd.isMap());
 
-			ensure_equals("dst counts come from src only", 3, dst["regions"][region1_handle_str]["get_other"]["resp_count"].asInteger());
+			ensure_equals("dst counts come from src only", s2_llsd["get_other"]["resp_count"].asInteger(), 3);
 
 			ensure_approximately_equals("dst minimum with count 0 does not contribute to merged minimum",
-										dst["regions"][region1_handle_str]["get_other"]["resp_min"].asReal(), F64(2.7), 20);
+										s2_llsd["get_other"]["resp_min"].asReal(), F64(2.7), 20);
 		}
 
 		// Other way around
@@ -862,16 +968,22 @@ namespace tut
 			LLSD src = s2.asLLSD(false);
 			LLSD dst = s1.asLLSD(false);
 
+			ensure_equals("merge src has single region", src["regions"].size(), 1);
+			ensure_equals("merge dst has single region", dst["regions"].size(), 1);
+			
 			// Remove time stamps, they're a problem
 			src.erase("duration");
-			src["regions"][region1_handle_str].erase("duration");
+			src["regions"][0].erase("duration");
 			dst.erase("duration");
-			dst["regions"][region1_handle_str].erase("duration");
+			dst["regions"][0].erase("duration");
+
+			LLSD s2_llsd = get_region(dst, region1_handle);
+			ensure("Region1 is present in dst", s2_llsd.isMap());
 
-			ensure_equals("dst counts come from src only (flipped)", 3, dst["regions"][region1_handle_str]["get_other"]["resp_count"].asInteger());
+			ensure_equals("dst counts come from src only (flipped)", s2_llsd["get_other"]["resp_count"].asInteger(), 3);
 
 			ensure_approximately_equals("dst minimum with count 0 does not contribute to merged minimum (flipped)",
-										dst["regions"][region1_handle_str]["get_other"]["resp_min"].asReal(), F64(2.7), 20);
+										s2_llsd["get_other"]["resp_min"].asReal(), F64(2.7), 20);
 		}
 	}
 
-- 
cgit v1.2.3


From 37cd8ad2a27188538c29fdcce58cf8ec6185231c Mon Sep 17 00:00:00 2001
From: Vadim ProductEngine <vsavchuk@productengine.com>
Date: Mon, 13 Dec 2010 13:38:46 +0200
Subject: STORM-781 FIXED Added support for editing multiple scripts within
 inventory of the same object using external editor.

The bug was caused by using the object ID as temporary file name for editing script,
which of course didn't work for multiple scripts in the same object inventory.

The fix is to use MD5("object id" + "script inventory item id") for the file name.
---
 indra/newview/llpreviewscript.cpp | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp
index 330e809c53..d0ebf047e8 100644
--- a/indra/newview/llpreviewscript.cpp
+++ b/indra/newview/llpreviewscript.cpp
@@ -2034,7 +2034,17 @@ bool LLLiveLSLEditor::writeToFile(const std::string& filename)
 
 std::string LLLiveLSLEditor::getTmpFileName()
 {
-	return std::string(LLFile::tmpdir()) + "sl_script_" + mObjectUUID.asString() + ".lsl";
+	// Take script inventory item id (within the object inventory)
+	// to consideration so that it's possible to edit multiple scripts
+	// in the same object inventory simultaneously (STORM-781).
+	std::string script_id = mObjectUUID.asString() + "_" + mItemUUID.asString();
+
+	// Use MD5 sum to make the file name shorter and not exceed maximum path length.
+	char script_id_hash_str[33];               /* Flawfinder: ignore */
+	LLMD5 script_id_hash((const U8 *)script_id.c_str());
+	script_id_hash.hex_digest(script_id_hash_str);
+
+	return std::string(LLFile::tmpdir()) + "sl_script_" + script_id_hash_str + ".lsl";
 }
 
 void LLLiveLSLEditor::uploadAssetViaCaps(const std::string& url,
-- 
cgit v1.2.3


From 622c9f772c5ca11d2c05c78e23761fae2467dd2f Mon Sep 17 00:00:00 2001
From: Monty Brandenberg <monty@lindenlab.com>
Date: Mon, 13 Dec 2010 11:17:41 -0500
Subject: Cleanup a cross-thread command dtor.  It was technically correct but
 looked a bit dodgy with pointer ownership.

---
 indra/newview/lltexturefetch.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index 88905372f6..e13fcf027f 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -1844,8 +1844,9 @@ LLTextureFetch::~LLTextureFetch()
 
 	while (! mCommands.empty())
 	{
-		delete mCommands.front();
+		TFRequest * req(mCommands.front());
 		mCommands.erase(mCommands.begin());
+		delete req;
 	}
 	
 	// ~LLQueuedThread() called here
-- 
cgit v1.2.3


From 31d401e1c3ccedfc06b9efda51923d050029cfc9 Mon Sep 17 00:00:00 2001
From: Vadim ProductEngine <vsavchuk@productengine.com>
Date: Mon, 13 Dec 2010 18:38:12 +0200
Subject: STORM-401 FIXED Add recepients of teleport offers to the recent
 people list.

---
 indra/newview/llviewermessage.cpp | 3 +++
 1 file changed, 3 insertions(+)

(limited to 'indra/newview')

diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index b7f72a2e4c..7313463f1b 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -6306,6 +6306,9 @@ bool handle_lure_callback(const LLSD& notification, const LLSD& response)
 				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();
-- 
cgit v1.2.3


From 29dc24a3ea8d6f3d3aa83fd6b22921937d0dd430 Mon Sep 17 00:00:00 2001
From: Paul Guslisty <pguslisty@productengine.com>
Date: Tue, 14 Dec 2010 14:53:51 +0200
Subject: STORM-713 FIXED XML/UI issues in llTextBox

- As the class LLToastNotifyPanel is deprecated, made the class LLToastScriptTextbox derived directly from LLToastPanel.

- Added callback for ignore button.

Now LLToastScriptTextbox has its own XML, therefore it's not needed to dynamically create toast panel.

Since LLToastNotifyPanel is deprecated all new notification toasts should be created this way.
---
 indra/newview/llscriptfloater.h                    |  4 +-
 indra/newview/lltoastscripttextbox.cpp             | 16 +++++-
 indra/newview/lltoastscripttextbox.h               | 13 +++--
 .../skins/default/xui/en/panel_notify_textbox.xml  | 66 +++++++++++++++-------
 4 files changed, 69 insertions(+), 30 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llscriptfloater.h b/indra/newview/llscriptfloater.h
index dc52baa115..8e959a3d0e 100644
--- a/indra/newview/llscriptfloater.h
+++ b/indra/newview/llscriptfloater.h
@@ -30,7 +30,7 @@
 #include "lltransientdockablefloater.h"
 #include "llnotificationptr.h"
 
-class LLToastNotifyPanel;
+class LLToastPanel;
 
 /**
  * Handles script notifications ("ScriptDialog" and "ScriptDialogGroup")
@@ -206,7 +206,7 @@ protected:
 private:
 	bool isScriptTextbox(LLNotificationPtr notification);
 
-	LLToastNotifyPanel* mScriptForm;
+	LLToastPanel* mScriptForm;
 	LLUUID mNotificationId;
 	LLUUID mObjectId;
 	bool mSaveFloaterPosition;
diff --git a/indra/newview/lltoastscripttextbox.cpp b/indra/newview/lltoastscripttextbox.cpp
index c013f521cc..2529ec865a 100644
--- a/indra/newview/lltoastscripttextbox.cpp
+++ b/indra/newview/lltoastscripttextbox.cpp
@@ -46,11 +46,16 @@
 
 const S32 LLToastScriptTextbox::DEFAULT_MESSAGE_MAX_LINE_COUNT= 7;
 
-LLToastScriptTextbox::LLToastScriptTextbox(LLNotificationPtr& notification)
-:	LLToastNotifyPanel(notification)
+LLToastScriptTextbox::LLToastScriptTextbox(const LLNotificationPtr& notification)
+:	LLToastPanel(notification)
 {
 	buildFromFile( "panel_notify_textbox.xml");
 
+	LLTextEditor* text_editorp = getChild<LLTextEditor>("text_editor_box");
+	text_editorp->setValue(notification->getMessage());
+
+	getChild<LLButton>("ignore_btn")->setClickedCallback(boost::bind(&LLToastScriptTextbox::onClickIgnore, this));
+
 	const LLSD& payload = notification->getPayload();
 
 	//message body
@@ -107,3 +112,10 @@ void LLToastScriptTextbox::onClickSubmit()
 		llwarns << response << llendl;
 	}
 }
+
+void LLToastScriptTextbox::onClickIgnore()
+{
+	LLSD response = mNotification->getResponseTemplate();
+	mNotification->respond(response);
+	close();
+}
diff --git a/indra/newview/lltoastscripttextbox.h b/indra/newview/lltoastscripttextbox.h
index ae3b545e0a..8e69d8834d 100644
--- a/indra/newview/lltoastscripttextbox.h
+++ b/indra/newview/lltoastscripttextbox.h
@@ -30,13 +30,11 @@
 #include "lltoastnotifypanel.h"
 #include "llnotificationptr.h"
 
-class LLButton;
-
 /**
  * Toast panel for scripted llTextbox notifications.
  */
 class LLToastScriptTextbox
-:	public LLToastNotifyPanel
+:	public LLToastPanel
 {
 public:
 	void close();
@@ -46,12 +44,15 @@ public:
 	// Non-transient messages.  You can specify non-default button
 	// layouts (like one for script dialogs) by passing various
 	// numbers in for "layout".
-	LLToastScriptTextbox(LLNotificationPtr& notification);
+	LLToastScriptTextbox(const LLNotificationPtr& notification);
 
 	/*virtual*/ ~LLToastScriptTextbox();
-protected:
-	void onClickSubmit();
+
 private:
+
+	void onClickSubmit();
+	void onClickIgnore();
+
 	static const S32 DEFAULT_MESSAGE_MAX_LINE_COUNT;
 };
 
diff --git a/indra/newview/skins/default/xui/en/panel_notify_textbox.xml b/indra/newview/skins/default/xui/en/panel_notify_textbox.xml
index 4634eeed46..d5b6057233 100644
--- a/indra/newview/skins/default/xui/en/panel_notify_textbox.xml
+++ b/indra/newview/skins/default/xui/en/panel_notify_textbox.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 <panel
    background_visible="true"
-   height="230"
+   height="220"
    label="instant_message"
    layout="topleft"
    left="0"
@@ -14,55 +14,81 @@
   <panel
    bevel_style="none"
    follows="left|right|top"
-   height="150"
+   height="185"
    label="info_panel"
    layout="topleft"
    left="0"
    name="info_panel"
    top="0"
-   width="305">
+   width="305">    
+    <text_editor
+     bg_readonly_color="0.0 0.0 0.0 0"
+     enabled="false"
+     follows="left|right|top|bottom"
+     font="SansSerif"
+     height="110" 
+     layout="topleft"
+     left="10"
+     mouse_opaque="false"
+     name="text_editor_box"
+     read_only="true"
+     text_color="white"
+     text_readonly_color="white"
+     top="10"
+     width="285"
+     wrap="true"
+     parse_highlights="true"
+     parse_urls="true"/>
     <text_editor
      parse_urls="true"
      enabled="true"
      follows="all"
-     height="60"
+     height="50"
      layout="topleft"
-     left="25"
+     left="10"
      max_length="250"
      name="message"
      parse_highlights="true"
      read_only="false"
-     top="40"
+     top_pad="10"
      type="string"
      use_ellipses="true"
      value="message"
-     width="260"
-     word_wrap="true" >
+     width="285"
+     word_wrap="true"
+     parse_url="false" >
     </text_editor>
-     parse_urls="false"
-    <button
-     top="110"
-     follows="top|left"
-     height="20"
-     label="Submit"
-     layout="topleft"
-     left="25"
-     name="btn_submit"
-     width="70" />
   </panel>
   <panel
      background_visible="false"
      follows="left|right|bottom"
-     height="0" 
+     height="25" 
      width="290"
      label="control_panel"
      layout="topleft"
      left="10"
      name="control_panel"
-     top_pad="5">
+     top_pad="0">
     <!-- 
 	 Notes:
 	 This panel holds the Ignore button and possibly other buttons of notification.
       -->
+    <button
+     top="0"
+     follows="top|left"
+     height="20"
+     label="Submit"
+     layout="topleft"
+     name="btn_submit"
+     width="70" />
+    <button
+     follows="top|right"
+     height="20"
+     label="Ignore"
+     layout="topleft"
+     left="215"
+     name="ignore_btn"
+     top="0"
+     width="70" />
   </panel>
 </panel>
-- 
cgit v1.2.3


From ff38b75bbf2c766af57834bc8d136d58a2a56f9d Mon Sep 17 00:00:00 2001
From: Paul Guslisty <pguslisty@productengine.com>
Date: Tue, 14 Dec 2010 17:04:22 +0200
Subject: STORM-434 FIXED Tooltips don't appear on Mini-Location bar.

- Added localized tooltips for icons and info button in LLPanelTopInfoBar
---
 indra/newview/llpaneltopinfobar.cpp | 9 +++++++++
 1 file changed, 9 insertions(+)

(limited to 'indra/newview')

diff --git a/indra/newview/llpaneltopinfobar.cpp b/indra/newview/llpaneltopinfobar.cpp
index a9ca7314ce..30949f8f02 100644
--- a/indra/newview/llpaneltopinfobar.cpp
+++ b/indra/newview/llpaneltopinfobar.cpp
@@ -38,6 +38,7 @@
 #include "llsidetray.h"
 #include "llslurl.h"
 #include "llstatusbar.h"
+#include "lltrans.h"
 #include "llviewercontrol.h"
 #include "llviewerinventory.h"
 #include "llviewermenu.h"
@@ -102,6 +103,13 @@ void LLPanelTopInfoBar::initParcelIcons()
 	mParcelIcon[SCRIPTS_ICON] = getChild<LLIconCtrl>("scripts_icon");
 	mParcelIcon[DAMAGE_ICON] = getChild<LLIconCtrl>("damage_icon");
 
+	mParcelIcon[VOICE_ICON]->setToolTip(LLTrans::getString("LocationCtrlVoiceTooltip"));
+	mParcelIcon[FLY_ICON]->setToolTip(LLTrans::getString("LocationCtrlFlyTooltip"));
+	mParcelIcon[PUSH_ICON]->setToolTip(LLTrans::getString("LocationCtrlPushTooltip"));
+	mParcelIcon[BUILD_ICON]->setToolTip(LLTrans::getString("LocationCtrlBuildTooltip"));
+	mParcelIcon[SCRIPTS_ICON]->setToolTip(LLTrans::getString("LocationCtrlScriptsTooltip"));
+	mParcelIcon[DAMAGE_ICON]->setToolTip(LLTrans::getString("LocationCtrlDamageTooltip"));
+
 	mParcelIcon[VOICE_ICON]->setMouseDownCallback(boost::bind(&LLPanelTopInfoBar::onParcelIconClick, this, VOICE_ICON));
 	mParcelIcon[FLY_ICON]->setMouseDownCallback(boost::bind(&LLPanelTopInfoBar::onParcelIconClick, this, FLY_ICON));
 	mParcelIcon[PUSH_ICON]->setMouseDownCallback(boost::bind(&LLPanelTopInfoBar::onParcelIconClick, this, PUSH_ICON));
@@ -129,6 +137,7 @@ BOOL LLPanelTopInfoBar::postBuild()
 {
 	mInfoBtn = getChild<LLButton>("place_info_btn");
 	mInfoBtn->setClickedCallback(boost::bind(&LLPanelTopInfoBar::onInfoButtonClicked, this));
+	mInfoBtn->setToolTip(LLTrans::getString("LocationCtrlInfoBtnTooltip"));
 
 	mParcelInfoText = getChild<LLTextBox>("parcel_info_text");
 	mDamageText = getChild<LLTextBox>("damage_text");
-- 
cgit v1.2.3


From a702b34394e4b38b27338eb6d68d22b498984118 Mon Sep 17 00:00:00 2001
From: Paul Guslisty <pguslisty@productengine.com>
Date: Tue, 14 Dec 2010 17:11:08 +0200
Subject: STORM-352 FIXED Vertical scrollbar isn't reshaped in resident profile
 panel after decreasing panel height

- Set height of scroll container the same as bounding panel's height
---
 indra/newview/skins/default/xui/en/panel_profile.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/skins/default/xui/en/panel_profile.xml b/indra/newview/skins/default/xui/en/panel_profile.xml
index 7caf425058..61e3bb354f 100644
--- a/indra/newview/skins/default/xui/en/panel_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_profile.xml
@@ -59,7 +59,7 @@
          left="0"
          name="profile_scroll"
          opaque="true"
-         height="527"
+         height="400"
          width="317"
          top="0">
           <panel
-- 
cgit v1.2.3


From 27f3470b7ecff97e5e7798a3cf120260c209fc42 Mon Sep 17 00:00:00 2001
From: Vadim ProductEngine <vsavchuk@productengine.com>
Date: Wed, 15 Dec 2010 15:44:06 +0200
Subject: STORM-786 FIXED Fixed disappearing controls in avatar picks list.

Caused by an improper fix of STORM-690.

Made the way we switch between profile view panels (profile view / pick_info / pick_edit)
more robust. It now suits both My Profile and Profile View panels.
---
 indra/newview/llpanelprofile.cpp | 126 +++++++++++++++++++++++++++++++++------
 indra/newview/llpanelprofile.h   |  29 ++++++++-
 2 files changed, 135 insertions(+), 20 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp
index 6038ab20d8..f4e8392916 100644
--- a/indra/newview/llpanelprofile.cpp
+++ b/indra/newview/llpanelprofile.cpp
@@ -114,9 +114,102 @@ public:
 LLAgentHandler gAgentHandler;
 
 
+//-- LLPanelProfile::ChildStack begins ----------------------------------------
+LLPanelProfile::ChildStack::ChildStack(LLPanel* parent)
+:	mParent(parent)
+{
+	llassert_always(parent != NULL);
+}
+
+/// Save current parent's child views and remove them from the child list.
+bool LLPanelProfile::ChildStack::push()
+{
+	view_list_t vlist = *mParent->getChildList();
+
+	for (view_list_t::const_iterator it = vlist.begin(); it != vlist.end(); ++it)
+	{
+		LLView* viewp = *it;
+		mParent->removeChild(viewp);
+	}
+
+	mStack.push_back(vlist);
+	dump();
+	return true;
+}
+
+/// Restore saved children (adding them back to the child list).
+bool LLPanelProfile::ChildStack::pop()
+{
+	if (mStack.size() == 0)
+	{
+		llwarns << "Empty stack" << llendl;
+		llassert(mStack.size() == 0);
+		return false;
+	}
+
+	view_list_t& top = mStack.back();
+	for (view_list_t::const_iterator it = top.begin(); it != top.end(); ++it)
+	{
+		LLView* viewp = *it;
+		mParent->addChild(viewp);
+	}
+
+	mStack.pop_back();
+	dump();
+	return true;
+}
+
+/// Temporarily add all saved children back.
+void LLPanelProfile::ChildStack::preParentReshape()
+{
+	mSavedStack = mStack;
+	while(mStack.size() > 0)
+	{
+		pop();
+	}
+}
+
+/// Add the temporarily saved children back.
+void LLPanelProfile::ChildStack::postParentReshape()
+{
+	mStack = mSavedStack;
+	mSavedStack = stack_t();
+
+	for (stack_t::const_iterator stack_it = mStack.begin(); stack_it != mStack.end(); ++stack_it)
+	{
+		const view_list_t& vlist = (*stack_it);
+		for (view_list_t::const_iterator list_it = vlist.begin(); list_it != vlist.end(); ++list_it)
+		{
+			LLView* viewp = *list_it;
+			lldebugs << "removing " << viewp->getName() << llendl;
+			mParent->removeChild(viewp);
+		}
+	}
+}
+
+void LLPanelProfile::ChildStack::dump()
+{
+	unsigned lvl = 0;
+	lldebugs << "child stack dump:" << llendl;
+	for (stack_t::const_iterator stack_it = mStack.begin(); stack_it != mStack.end(); ++stack_it, ++lvl)
+	{
+		std::ostringstream dbg_line;
+		dbg_line << "lvl #" << lvl << ":";
+		const view_list_t& vlist = (*stack_it);
+		for (view_list_t::const_iterator list_it = vlist.begin(); list_it != vlist.end(); ++list_it)
+		{
+			dbg_line << " " << (*list_it)->getName();
+		}
+		lldebugs << dbg_line.str() << llendl;
+	}
+}
+
+//-- LLPanelProfile::ChildStack ends ------------------------------------------
+
 LLPanelProfile::LLPanelProfile()
  : LLPanel()
  , mTabCtrl(NULL)
+ , mChildStack(this)
  , mAvatarId(LLUUID::null)
 {
 }
@@ -136,6 +229,15 @@ BOOL LLPanelProfile::postBuild()
 	return TRUE;
 }
 
+// virtual
+void LLPanelProfile::reshape(S32 width, S32 height, BOOL called_from_parent)
+{
+	// Temporarily add saved children back and reshape them.
+	mChildStack.preParentReshape();
+	LLPanel::reshape(width, height, called_from_parent);
+	mChildStack.postParentReshape();
+}
+
 void LLPanelProfile::onOpen(const LLSD& key)
 {
 	// open the desired panel
@@ -177,7 +279,6 @@ void LLPanelProfile::onOpen(const LLSD& key)
 	}
 }
 
-//*TODO redo panel toggling
 void LLPanelProfile::togglePanel(LLPanel* panel, const LLSD& key)
 {
 	// TRUE - we need to open/expand "panel"
@@ -204,21 +305,10 @@ void LLPanelProfile::onTabSelected(const LLSD& param)
 	}
 }
 
-void LLPanelProfile::setAllChildrenVisible(BOOL visible)
-{
-	const child_list_t* child_list = getChildList();
-	child_list_const_iter_t child_it = child_list->begin();
-	for (; child_it != child_list->end(); ++child_it)
-	{
-		LLView* viewp = *child_it;
-		viewp->setVisible(visible);
-	}
-}
-
 void LLPanelProfile::openPanel(LLPanel* panel, const LLSD& params)
 {
 	// Hide currently visible panel (STORM-690).
-	setAllChildrenVisible(FALSE);
+	mChildStack.push();
 
 	// Add the panel or bring it to front.
 	if (panel->getParent() != this)
@@ -231,7 +321,7 @@ void LLPanelProfile::openPanel(LLPanel* panel, const LLSD& params)
 	}
 
 	panel->setVisible(TRUE);
-
+	panel->setFocus(TRUE); // prevent losing focus by the floater
 	panel->onOpen(params);
 
 	LLRect new_rect = getRect();
@@ -249,15 +339,17 @@ void LLPanelProfile::closePanel(LLPanel* panel)
 		removeChild(panel);
 
 		// Make the underlying panel visible.
+		mChildStack.pop();
+
+		// Prevent losing focus by the floater
 		const child_list_t* child_list = getChildList();
 		if (child_list->size() > 0)
 		{
-			child_list->front()->setVisible(TRUE);
-			child_list->front()->setFocus(TRUE); // prevent losing focus by the floater
+			child_list->front()->setFocus(TRUE);
 		}
 		else
 		{
-			llwarns << "No underlying panel to make visible." << llendl;
+			llwarns << "No underlying panel to focus." << llendl;
 		}
 	}
 }
diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h
index d2bcee8076..577b71f284 100644
--- a/indra/newview/llpanelprofile.h
+++ b/indra/newview/llpanelprofile.h
@@ -41,7 +41,7 @@ class LLPanelProfile : public LLPanel
 
 public:
 	/*virtual*/ BOOL postBuild();
-
+	/*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
 	/*virtual*/ void onOpen(const LLSD& key);
 
 	virtual void togglePanel(LLPanel*, const LLSD& key = LLSD());
@@ -58,8 +58,6 @@ protected:
 
 	virtual void onTabSelected(const LLSD& param);
 
-	virtual void setAllChildrenVisible(BOOL visible);
-
 	LLTabContainer* getTabCtrl() { return mTabCtrl; }
 
 	const LLUUID& getAvatarId() { return mAvatarId; }
@@ -72,8 +70,33 @@ protected:
 
 private:
 
+	//-- ChildStack begins ----------------------------------------------------
+	class ChildStack
+	{
+		LOG_CLASS(LLPanelProfile::ChildStack);
+	public:
+		ChildStack(LLPanel* parent);
+
+		bool push();
+		bool pop();
+		void preParentReshape();
+		void postParentReshape();
+
+	private:
+		void dump();
+
+		typedef LLView::child_list_t view_list_t;
+		typedef std::list<view_list_t> stack_t;
+
+		stack_t		mStack;
+		stack_t		mSavedStack;
+		LLPanel*	mParent;
+	};
+	//-- ChildStack ends ------------------------------------------------------
+
 	LLTabContainer* mTabCtrl;	
 	profile_tabs_t mTabContainer;
+	ChildStack		mChildStack;
 	LLUUID mAvatarId;
 };
 
-- 
cgit v1.2.3


From 10d9328b86991272b6cbc7eda73e8f09afccfb52 Mon Sep 17 00:00:00 2001
From: Vadim ProductEngine <vsavchuk@productengine.com>
Date: Wed, 15 Dec 2010 16:00:37 +0200
Subject: STORM-786 ADDITIONAL FIX Fixed Windows build.

---
 indra/newview/llpanelprofile.cpp | 11 ++++++++---
 indra/newview/llpanelprofile.h   |  3 ++-
 2 files changed, 10 insertions(+), 4 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp
index f4e8392916..b035d7d473 100644
--- a/indra/newview/llpanelprofile.cpp
+++ b/indra/newview/llpanelprofile.cpp
@@ -115,10 +115,15 @@ LLAgentHandler gAgentHandler;
 
 
 //-- LLPanelProfile::ChildStack begins ----------------------------------------
-LLPanelProfile::ChildStack::ChildStack(LLPanel* parent)
-:	mParent(parent)
+LLPanelProfile::ChildStack::ChildStack()
+:	mParent(NULL)
+{
+}
+
+void LLPanelProfile::ChildStack::setParent(LLPanel* parent)
 {
 	llassert_always(parent != NULL);
+	mParent = parent;
 }
 
 /// Save current parent's child views and remove them from the child list.
@@ -209,9 +214,9 @@ void LLPanelProfile::ChildStack::dump()
 LLPanelProfile::LLPanelProfile()
  : LLPanel()
  , mTabCtrl(NULL)
- , mChildStack(this)
  , mAvatarId(LLUUID::null)
 {
+	mChildStack.setParent(this);
 }
 
 BOOL LLPanelProfile::postBuild()
diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h
index 577b71f284..0a572e6f25 100644
--- a/indra/newview/llpanelprofile.h
+++ b/indra/newview/llpanelprofile.h
@@ -75,7 +75,8 @@ private:
 	{
 		LOG_CLASS(LLPanelProfile::ChildStack);
 	public:
-		ChildStack(LLPanel* parent);
+		ChildStack();
+		void setParent(LLPanel* parent);
 
 		bool push();
 		bool pop();
-- 
cgit v1.2.3


From bd53ba004a522d7c0448cdbf2b5f35b6aebd8397 Mon Sep 17 00:00:00 2001
From: Wolfpup Lowenhar <wolfpup67@earthlink.net>
Date: Wed, 15 Dec 2010 09:53:24 -0500
Subject: STORM-776 : unable to change permissions to "no trans" on item in
 avatar inventory    applied Kitty's code changes listed in STROM-288 as it is
 a related issue and this    actualy fixed both issues!

---
 indra/newview/llsidepaneliteminfo.cpp | 9 +++++++--
 indra/newview/llsidepaneliteminfo.h   | 1 +
 2 files changed, 8 insertions(+), 2 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp
index be797ea937..c8c6858b81 100644
--- a/indra/newview/llsidepaneliteminfo.cpp
+++ b/indra/newview/llsidepaneliteminfo.cpp
@@ -71,12 +71,12 @@ void LLItemPropertiesObserver::changed(U32 mask)
 	const std::set<LLUUID>& mChangedItemIDs = gInventory.getChangedIDs();
 	std::set<LLUUID>::const_iterator it;
 
-	const LLUUID& object_id = mFloater->getObjectID();
+	const LLUUID& item_id = mFloater->getItemID();
 
 	for (it = mChangedItemIDs.begin(); it != mChangedItemIDs.end(); it++)
 	{
 		// set dirty for 'item profile panel' only if changed item is the item for which 'item profile panel' is shown (STORM-288)
-		if (*it == object_id)
+		if (*it == item_id)
 		{
 			// if there's a change we're interested in.
 			if((mask & (LLInventoryObserver::LABEL | LLInventoryObserver::INTERNAL | LLInventoryObserver::REMOVE)) != 0)
@@ -196,6 +196,11 @@ const LLUUID& LLSidepanelItemInfo::getObjectID() const
 	return mObjectID;
 }
 
+const LLUUID& LLSidepanelItemInfo::getItemID() const
+{
+	return mItemID;
+}
+
 void LLSidepanelItemInfo::reset()
 {
 	LLSidepanelInventorySubpanel::reset();
diff --git a/indra/newview/llsidepaneliteminfo.h b/indra/newview/llsidepaneliteminfo.h
index 6416e2cfe4..25be145f64 100644
--- a/indra/newview/llsidepaneliteminfo.h
+++ b/indra/newview/llsidepaneliteminfo.h
@@ -55,6 +55,7 @@ public:
 	void setEditMode(BOOL edit);
 
 	const LLUUID& getObjectID() const;
+	const LLUUID& getItemID() const;
 
 protected:
 	/*virtual*/ void refresh();
-- 
cgit v1.2.3


From 0f1d337a1e20d2d0f2b16e5df7e94c64a95ca6f0 Mon Sep 17 00:00:00 2001
From: Kitty Barnett <develop@catznip.com>
Date: Wed, 15 Dec 2010 20:40:47 +0100
Subject: STORM-799 FIXED Crash in LLVivoxVoiceClient::notifyStatusObservers()

---
 indra/newview/llpanelavatar.cpp | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp
index 1249d5d856..a9bcdef47c 100644
--- a/indra/newview/llpanelavatar.cpp
+++ b/indra/newview/llpanelavatar.cpp
@@ -341,10 +341,11 @@ LLPanelAvatarNotes::~LLPanelAvatarNotes()
 	if(getAvatarId().notNull())
 	{
 		LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this);
-		if(LLVoiceClient::instanceExists())
-		{
-			LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this);
-		}
+	}
+
+	if(LLVoiceClient::instanceExists())
+	{
+		LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this);
 	}
 }
 
@@ -758,10 +759,11 @@ LLPanelAvatarProfile::~LLPanelAvatarProfile()
 	if(getAvatarId().notNull())
 	{
 		LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this);
-		if(LLVoiceClient::instanceExists())
-		{
-			LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this);
-		}
+	}
+
+	if(LLVoiceClient::instanceExists())
+	{
+		LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this);
 	}
 }
 
-- 
cgit v1.2.3


From b854cde9a012b83dd6eaeddea6a1e60b17435534 Mon Sep 17 00:00:00 2001
From: Kitty Barnett <develop@catznip.com>
Date: Wed, 15 Dec 2010 20:02:53 +0100
Subject: STORM-800 FIXED Crash in
 LLRemoteParcelInfoProcessor::processParcelInfoReply()

---
 indra/newview/llremoteparcelrequest.cpp | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llremoteparcelrequest.cpp b/indra/newview/llremoteparcelrequest.cpp
index 0dff087553..e5ef51bdd1 100644
--- a/indra/newview/llremoteparcelrequest.cpp
+++ b/indra/newview/llremoteparcelrequest.cpp
@@ -140,22 +140,25 @@ void LLRemoteParcelInfoProcessor::processParcelInfoReply(LLMessageSystem* msg, v
 	typedef std::vector<observer_multimap_t::iterator> deadlist_t;
 	deadlist_t dead_iters;
 
-	observer_multimap_t::iterator oi;
-	observer_multimap_t::iterator start = observers.lower_bound(parcel_data.parcel_id);
+	observer_multimap_t::iterator oi = observers.lower_bound(parcel_data.parcel_id);
 	observer_multimap_t::iterator end = observers.upper_bound(parcel_data.parcel_id);
 
-	for (oi = start; oi != end; ++oi)
+	while (oi != end)
 	{
-		LLRemoteParcelInfoObserver * observer = oi->second.get();
+		// increment the loop iterator now since it may become invalid below
+		observer_multimap_t::iterator cur_oi = oi++;
+
+		LLRemoteParcelInfoObserver * observer = cur_oi->second.get();
 		if(observer)
 		{
+			// may invalidate cur_oi if the observer removes itself 
 			observer->processParcelInfo(parcel_data);
 		}
 		else
 		{
 			// the handle points to an expired observer, so don't keep it
 			// around anymore
-			dead_iters.push_back(oi);
+			dead_iters.push_back(cur_oi);
 		}
 	}
 
-- 
cgit v1.2.3


From de8fa40209300a92a595be59073a2f0cb258e15b Mon Sep 17 00:00:00 2001
From: Monty Brandenberg <monty@lindenlab.com>
Date: Wed, 15 Dec 2010 15:50:09 -0500
Subject: ESC-235 Truncation of over-sized metrics reports wasn't working.
 Legacy of the LLSD::Map-to-LLSD::Array conversion, this ended up performing
 an erase on the array rather than the map taking out all the regions.  So,
 there *was* a metrics report, it was just empty of regions.  Fixed and
 scanned for more array/map problems and corrected the data type for duration
 sorts (should have been Real).

---
 indra/newview/lltexturefetch.cpp | 26 ++++++++++++++------------
 1 file changed, 14 insertions(+), 12 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index e13fcf027f..25ad2fe717 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -2974,25 +2974,27 @@ truncate_viewer_metrics(int max_regions, LLSD & metrics)
 	}
 
 	// Build map of region hashes ordered by duration
-	typedef std::multimap<LLSD::Integer, LLSD::String> reg_ordered_list_t;
+	typedef std::multimap<LLSD::Real, int> reg_ordered_list_t;
 	reg_ordered_list_t regions_by_duration;
 
-	LLSD::map_const_iterator it_end(reg_map.endMap());
-	for (LLSD::map_const_iterator it(reg_map.beginMap()); it_end != it; ++it)
+	int ind(0);
+	LLSD::array_const_iterator it_end(reg_map.endArray());
+	for (LLSD::array_const_iterator it(reg_map.beginArray()); it_end != it; ++it, ++ind)
 	{
-		LLSD::Integer duration = (it->second)[duration_tag].asInteger();
-		regions_by_duration.insert(reg_ordered_list_t::value_type(duration, it->first));
+		LLSD::Real duration = (*it)[duration_tag].asReal();
+		regions_by_duration.insert(reg_ordered_list_t::value_type(duration, ind));
 	}
 
-	// Erase excess region reports selecting shortest duration first
-	reg_ordered_list_t::const_iterator it2_end(regions_by_duration.end());
-	reg_ordered_list_t::const_iterator it2(regions_by_duration.begin());
-	int limit(regions_by_duration.size() - max_regions);
-	for (int i(0); i < limit && it2_end != it2; ++i, ++it2)
+	// Build a replacement regions array with the longest-persistence regions
+	LLSD new_region(LLSD::emptyArray());
+	reg_ordered_list_t::const_reverse_iterator it2_end(regions_by_duration.rend());
+	reg_ordered_list_t::const_reverse_iterator it2(regions_by_duration.rbegin());
+	for (int i(0); i < max_regions && it2_end != it2; ++i, ++it2)
 	{
-		reg_map.erase(it2->second);
+		new_region.append(reg_map[it2->second]);
 	}
-
+	reg_map = new_region;
+	
 	return true;
 }
 
-- 
cgit v1.2.3


From 73962e2134035855def0177db171d8eddaa193cb Mon Sep 17 00:00:00 2001
From: Seth ProductEngine <slitovchuk@productengine.com>
Date: Thu, 16 Dec 2010 00:50:03 +0200
Subject: STORM-771 FIXED Pasting wearable items from clipboard to Current
 Outfit or an outfit folder now creates links to these items.

---
 indra/newview/llinventorybridge.cpp | 30 +++++++++++++++++++++++++++---
 1 file changed, 27 insertions(+), 3 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 5ba87423c7..ab0acbae50 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -104,6 +104,7 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_
 bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, LLMoveInv*);
 bool confirm_attachment_rez(const LLSD& notification, const LLSD& response);
 void teleport_via_landmark(const LLUUID& asset_id);
+static BOOL can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit);
 
 // +=================================================+
 // |        LLInvFVBridge                            |
@@ -2341,6 +2342,10 @@ void LLFolderBridge::pasteFromClipboard()
 	LLInventoryModel* model = getInventoryModel();
 	if(model && isClipboardPasteable())
 	{
+		const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
+		const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
+		const BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT);
+
 		const LLUUID parent_id(mUUID);
 
 		LLDynamicArray<LLUUID> objects;
@@ -2353,7 +2358,14 @@ void LLFolderBridge::pasteFromClipboard()
 			LLInventoryItem *item = model->getItem(item_id);
 			if (item)
 			{
-				if(LLInventoryClipboard::instance().isCutMode())
+				if (move_is_into_current_outfit || move_is_into_outfit)
+				{
+					if (can_move_to_outfit(item, move_is_into_current_outfit))
+					{
+						dropToOutfit(item, move_is_into_current_outfit);
+					}
+				}
+				else if(LLInventoryClipboard::instance().isCutMode())
 				{
 					// move_inventory_item() is not enough,
 					//we have to update inventory locally too
@@ -2381,9 +2393,13 @@ void LLFolderBridge::pasteFromClipboard()
 
 void LLFolderBridge::pasteLinkFromClipboard()
 {
-	const LLInventoryModel* model = getInventoryModel();
+	LLInventoryModel* model = getInventoryModel();
 	if(model)
 	{
+		const LLUUID &current_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false);
+		const BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
+		const BOOL move_is_into_outfit = (getCategory() && getCategory()->getPreferredType()==LLFolderType::FT_OUTFIT);
+
 		const LLUUID parent_id(mUUID);
 
 		LLDynamicArray<LLUUID> objects;
@@ -2393,7 +2409,15 @@ void LLFolderBridge::pasteLinkFromClipboard()
 			 ++iter)
 		{
 			const LLUUID &object_id = (*iter);
-			if (LLInventoryCategory *cat = model->getCategory(object_id))
+			if (move_is_into_current_outfit || move_is_into_outfit)
+			{
+				LLInventoryItem *item = model->getItem(object_id);
+				if (item && can_move_to_outfit(item, move_is_into_current_outfit))
+				{
+					dropToOutfit(item, move_is_into_current_outfit);
+				}
+			}
+			else if (LLInventoryCategory *cat = model->getCategory(object_id))
 			{
 				const std::string empty_description = "";
 				link_inventory_item(
-- 
cgit v1.2.3


From 317f5ecf93395a6fc00f1d0271db6d35f76650e7 Mon Sep 17 00:00:00 2001
From: Vadim ProductEngine <vsavchuk@productengine.com>
Date: Thu, 16 Dec 2010 14:59:10 +0200
Subject: STORM-529 FIXED Added Undo/Redo items to the Build menu.

---
 indra/newview/skins/default/xui/en/menu_viewer.xml | 23 ++++++++++++++++++++++
 1 file changed, 23 insertions(+)

(limited to 'indra/newview')

diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 907f68dc06..3b1ebc64ab 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -976,6 +976,29 @@
                  parameter="perm_prefs" />
             </menu_item_call>
         </menu>
+        <menu_item_separator/>
+        <menu_item_call
+         enabled="false"
+         label="Undo"
+         name="Undo"
+         shortcut="control|Z">
+            <on_click
+             function="Edit.Undo"
+             userdata="" />
+            <on_enable
+             function="Edit.EnableUndo" />
+        </menu_item_call>
+        <menu_item_call
+         enabled="false"
+         label="Redo"
+         name="Redo"
+         shortcut="control|Y">
+            <on_click
+             function="Edit.Redo"
+             userdata="" />
+            <on_enable
+             function="Edit.EnableRedo" />
+        </menu_item_call>        
     </menu>
     <menu
      create_jump_keys="true"
-- 
cgit v1.2.3


From 3c05ebd28635e867f9726062b08cdbf4a7b53b22 Mon Sep 17 00:00:00 2001
From: Monty Brandenberg <monty@lindenlab.com>
Date: Thu, 16 Dec 2010 16:42:26 -0800
Subject: ESC-237 No static init of LLAtomics and move TFRequest out of unnamed
 namespace. Linux startup crash appears to be due to static/global C++ init of
 LLAtomic types.  The initializer with explicit value makes some runtime calls
 and it looks like these assume, at least on Linux, that apr_initialize() has
 been called.  So move the static POST count to a member and provide accessors
 and increment/decrement.  Command queue was built on a pointer to a class in
 anonymous namespace and that's not quite valid.  Made it a nested class
 (really a nested forward declaration) while keeping the derived classes in
 anonymous.

---
 indra/newview/lltexturefetch.cpp | 42 ++++++++++++++++++----------------------
 indra/newview/lltexturefetch.h   | 16 +++++++++++++--
 2 files changed, 33 insertions(+), 25 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index 25ad2fe717..4f63abb152 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -388,9 +388,6 @@ private:
 
 // Cross-thread messaging for asset metrics.
 
-namespace
-{
-
 /**
  * @brief Base class for cross-thread requests made of the fetcher
  *
@@ -490,7 +487,7 @@ namespace
  *       (i.e. deep copy) when necessary.
  *
  */
-class TFRequest // : public LLQueuedThread::QueuedRequest
+class LLTextureFetch::TFRequest // : public LLQueuedThread::QueuedRequest
 {
 public:
 	// Default ctors and assignment operator are correct.
@@ -505,6 +502,8 @@ public:
 	virtual bool doWork(LLTextureFetch * fetcher) = 0;
 };
 
+namespace 
+{
 
 /**
  * @brief Implements a 'Set Region' cross-thread command.
@@ -517,11 +516,11 @@ public:
  *
  * Corresponds to LLTextureFetch::commandSetRegion()
  */
-class TFReqSetRegion : public TFRequest
+class TFReqSetRegion : public LLTextureFetch::TFRequest
 {
 public:
 	TFReqSetRegion(U64 region_handle)
-		: TFRequest(),
+		: LLTextureFetch::TFRequest(),
 		  mRegionHandle(region_handle)
 		{}
 	TFReqSetRegion & operator=(const TFReqSetRegion &);	// Not defined
@@ -550,7 +549,7 @@ public:
  *
  * Corresponds to LLTextureFetch::commandSendMetrics()
  */
-class TFReqSendMetrics : public TFRequest
+class TFReqSendMetrics : public LLTextureFetch::TFRequest
 {
 public:
     /**
@@ -574,7 +573,7 @@ public:
 					 const LLUUID & session_id,
 					 const LLUUID & agent_id,
 					 LLViewerAssetStats * main_stats)
-		: TFRequest(),
+		: LLTextureFetch::TFRequest(),
 		  mCapsURL(caps_url),
 		  mSessionID(session_id),
 		  mAgentID(agent_id),
@@ -593,14 +592,6 @@ public:
 	LLViewerAssetStats * mMainStats;
 };
 
-/*
- * Count of POST requests outstanding.  We maintain the count
- * indirectly in the CURL request responder's ctor and dtor and
- * use it when determining whether or not to sleep the thread.  Can't
- * use the LLCurl module's request counter as it isn't thread compatible.
- */
-LLAtomic32<S32> curl_post_request_count = 0;
-
 /*
  * Examines the merged viewer metrics report and if found to be too long,
  * will attempt to truncate it in some reasonable fashion.
@@ -1834,6 +1825,7 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image
 	  mCurlGetRequest(NULL),
 	  mQAMode(qa_mode)
 {
+	mCurlPOSTRequestCount = 0;
 	mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS");
 	mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), gSavedSettings.getU32("TextureLoggingThreshold"));
 }
@@ -2149,7 +2141,7 @@ S32 LLTextureFetch::getPending()
         LLMutexLock lock(&mQueueMutex);
         
         res = mRequestQueue.size();
-        res += curl_post_request_count;
+        res += mCurlPOSTRequestCount;
         res += mCommands.size();
     }
 	unlockData();
@@ -2175,7 +2167,7 @@ bool LLTextureFetch::runCondition()
 		have_no_commands = mCommands.empty();
 	}
 	
-    bool have_no_curl_requests(0 == curl_post_request_count);
+    bool have_no_curl_requests(0 == mCurlPOSTRequestCount);
 	
 	return ! (have_no_commands
 			  && have_no_curl_requests
@@ -2769,7 +2761,7 @@ void LLTextureFetch::cmdEnqueue(TFRequest * req)
 	unpause();
 }
 
-TFRequest * LLTextureFetch::cmdDequeue()
+LLTextureFetch::TFRequest * LLTextureFetch::cmdDequeue()
 {
 	TFRequest * ret = 0;
 	
@@ -2856,22 +2848,24 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
 	class lcl_responder : public LLCurl::Responder
 	{
 	public:
-		lcl_responder(S32 expected_sequence,
+		lcl_responder(LLTextureFetch * fetcher,
+					  S32 expected_sequence,
                       volatile const S32 & live_sequence,
                       volatile bool & reporting_break,
 					  volatile bool & reporting_started)
 			: LLCurl::Responder(),
+			  mFetcher(fetcher),
               mExpectedSequence(expected_sequence),
               mLiveSequence(live_sequence),
 			  mReportingBreak(reporting_break),
 			  mReportingStarted(reporting_started)
 			{
-                curl_post_request_count++;
+                mFetcher->incrCurlPOSTCount();
             }
         
         ~lcl_responder()
             {
-                curl_post_request_count--;
+                mFetcher->decrCurlPOSTCount();
             }
 
 		// virtual
@@ -2896,6 +2890,7 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
 			}
 
 	private:
+		LLTextureFetch * mFetcher;
         S32 mExpectedSequence;
         volatile const S32 & mLiveSequence;
 		volatile bool & mReportingBreak;
@@ -2939,7 +2934,8 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
 		fetcher->getCurlRequest().post(mCapsURL,
 									   headers,
 									   merged_llsd,
-									   new lcl_responder(report_sequence,
+									   new lcl_responder(fetcher,
+														 report_sequence,
                                                          report_sequence,
                                                          LLTextureFetch::svMetricsDataBreak,
 														 reporting_started));
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index a8fd3ce244..ad00a7ea36 100644
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -33,6 +33,7 @@
 #include "llworkerthread.h"
 #include "llcurl.h"
 #include "lltextureinfo.h"
+#include "llapr.h"
 
 class LLViewerTexture;
 class LLTextureFetchWorker;
@@ -42,8 +43,6 @@ class LLImageDecodeThread;
 class LLHost;
 class LLViewerAssetStats;
 
-namespace { class TFRequest; }
-
 // Interface class
 class LLTextureFetch : public LLWorkerThread
 {
@@ -54,6 +53,8 @@ public:
 	LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded, bool qa_mode);
 	~LLTextureFetch();
 
+	class TFRequest;
+	
 	/*virtual*/ S32 update(U32 max_time_ms);	
 	void shutDownTextureCacheThread() ; //called in the main thread after the TextureCacheThread shuts down.
 	void shutDownImageDecodeThread() ;  //called in the main thread after the ImageDecodeThread shuts down.
@@ -100,6 +101,10 @@ public:
 
 	bool isQAMode() const				{ return mQAMode; }
 
+	// Curl POST counter maintenance
+	inline void incrCurlPOSTCount()		{ mCurlPOSTRequestCount++; }
+	inline void decrCurlPOSTCount()		{ mCurlPOSTRequestCount--; }
+
 protected:
 	void addToNetworkQueue(LLTextureFetchWorker* worker);
 	void removeFromNetworkQueue(LLTextureFetchWorker* worker, bool cancel);
@@ -187,6 +192,13 @@ private:
 
 	// If true, modifies some behaviors that help with QA tasks.
 	const bool mQAMode;
+
+	// Count of POST requests outstanding.  We maintain the count
+	// indirectly in the CURL request responder's ctor and dtor and
+	// use it when determining whether or not to sleep the thread.  Can't
+	// use the LLCurl module's request counter as it isn't thread compatible.
+	// *NOTE:  Don't mix Atomic and static, apr_initialize must be called first.
+	LLAtomic32<S32> mCurlPOSTRequestCount;
 	
 public:
 	// A probabilistically-correct indicator that the current
-- 
cgit v1.2.3


From 085a8b260d6cdb83c42fd98579a4ef5971bbc893 Mon Sep 17 00:00:00 2001
From: Paul Guslisty <pguslisty@productengine.com>
Date: Sat, 18 Dec 2010 12:18:03 +0200
Subject: STORM-801 FIXED Wrong checkbox label in panel preferences, advanced
 tab

- Corrected checkbox label
---
 indra/newview/skins/default/xui/en/panel_preferences_advanced.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
index d6e4c56113..37aab059a9 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
@@ -82,7 +82,7 @@
      control_name="AllowMultipleViewers"
      follows="top|left"
      height="15"
-     label="Allow Multiple Viewer"
+     label="Allow Multiple Viewers"
      layout="topleft"
      left="30"
      name="allow_multiple_viewer_check"
-- 
cgit v1.2.3


From b59dad36ba7b6d45c25f596e690df3150d94f1b4 Mon Sep 17 00:00:00 2001
From: Paul Guslisty <pguslisty@productengine.com>
Date: Sat, 18 Dec 2010 14:00:47 +0200
Subject: STORM-412 FIXED Resident profile controls aren't reshaped on changing
 panel width

- Added parameters for text boxes to follow right side of panel
---
 .../newview/skins/default/xui/en/panel_my_profile.xml  | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/skins/default/xui/en/panel_my_profile.xml b/indra/newview/skins/default/xui/en/panel_my_profile.xml
index 1b41f602cd..5b8abaca6f 100644
--- a/indra/newview/skins/default/xui/en/panel_my_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_my_profile.xml
@@ -185,7 +185,7 @@
               </expandable_text>
             </panel>
             <text
-             follows="left|top"
+             follows="left|top|right"
              height="15"
        font.style="BOLD"
        font="SansSerifMedium"
@@ -200,7 +200,7 @@
              use_ellipses="true"
          />
             <text
-             follows="left|top"
+             follows="left|top|right"
            font.style="BOLD"
              height="10"
              layout="topleft"
@@ -213,7 +213,7 @@
             <text_editor
              allow_scroll="false"
              bg_visible="false"
-             follows="left|top"
+             follows="left|top|right"
              h_pad="0"
              height="15"
              layout="topleft"
@@ -226,7 +226,7 @@
              width="300"
              word_wrap="true" />
             <text
-             follows="left|top"
+             follows="left|top|right"
        font.style="BOLD"
              height="15"
              layout="topleft"
@@ -250,7 +250,7 @@
             <text_editor
             allow_scroll="false"
             bg_visible="false"
-            follows="left|top"
+            follows="left|top|right"
             h_pad="0"
             height="28"
             layout="topleft"
@@ -266,7 +266,7 @@
               Linden.
             </text_editor>
             <text
-             follows="left|top"
+             follows="left|top|right"
        font.style="BOLD"
              height="15"
              layout="topleft"
@@ -277,7 +277,7 @@
              value="Partner:"
              width="300" />
             <panel
-             follows="left|top"
+             follows="left|top|right"
              height="15"
              layout="topleft"
              left="10"
@@ -285,7 +285,7 @@
              top_pad="0"
              width="300">
               <text
-               follows="left|top"
+               follows="left|top|right"
                height="10"
                initial_value="(retrieving)"
                layout="topleft"
@@ -297,7 +297,7 @@
            width="300" />
             </panel>
             <text
-             follows="left|top"
+             follows="left|top|right"
        font.style="BOLD"
              height="13"
              layout="topleft"
-- 
cgit v1.2.3


From 1718ca48c22999986cd52acec71971bab486b490 Mon Sep 17 00:00:00 2001
From: Vadim ProductEngine <vsavchuk@productengine.com>
Date: Sat, 18 Dec 2010 20:17:36 +0200
Subject: STORM-511 FIXED Display tooltip for sender name on group notices.

Changes:
* Set tooltip for sender name.
* Overridden handleTooltip() for the tooltip to be of normal (yellow) color.
---
 indra/newview/llinspecttoast.cpp          | 11 +++++++++++
 indra/newview/lltoastgroupnotifypanel.cpp |  1 +
 2 files changed, 12 insertions(+)

(limited to 'indra/newview')

diff --git a/indra/newview/llinspecttoast.cpp b/indra/newview/llinspecttoast.cpp
index 58b3f0309f..d7b82667d1 100644
--- a/indra/newview/llinspecttoast.cpp
+++ b/indra/newview/llinspecttoast.cpp
@@ -46,6 +46,7 @@ public:
 	virtual ~LLInspectToast();
 
 	/*virtual*/ void onOpen(const LLSD& notification_id);
+	/*virtual*/ BOOL handleToolTip(S32 x, S32 y, MASK mask);
 private:
 	void onToastDestroy(LLToast * toast);
 
@@ -73,6 +74,7 @@ LLInspectToast::~LLInspectToast()
 	LLTransientFloaterMgr::getInstance()->removeControlView(this);
 }
 
+// virtual
 void LLInspectToast::onOpen(const LLSD& notification_id)
 {
 	LLInspect::onOpen(notification_id);
@@ -103,6 +105,15 @@ void LLInspectToast::onOpen(const LLSD& notification_id)
 	LLUI::positionViewNearMouse(this);
 }
 
+// virtual
+BOOL LLInspectToast::handleToolTip(S32 x, S32 y, MASK mask)
+{
+	// We don't like the way LLInspect handles tooltips
+	// (black tooltips look weird),
+	// so force using the default implementation (STORM-511).
+	return LLFloater::handleToolTip(x, y, mask);
+}
+
 void LLInspectToast::onToastDestroy(LLToast * toast)
 {
 	closeFloater(false);
diff --git a/indra/newview/lltoastgroupnotifypanel.cpp b/indra/newview/lltoastgroupnotifypanel.cpp
index 563c27c4d7..75178a6ef8 100644
--- a/indra/newview/lltoastgroupnotifypanel.cpp
+++ b/indra/newview/lltoastgroupnotifypanel.cpp
@@ -77,6 +77,7 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(LLNotificationPtr& notification
 	from << from_name << "/" << groupData.mName;
 	LLTextBox* pTitleText = getChild<LLTextBox>("title");
 	pTitleText->setValue(from.str());
+	pTitleText->setToolTip(from.str());
 
 	//message subject
 	const std::string& subject = payload["subject"].asString();
-- 
cgit v1.2.3