diff options
Diffstat (limited to 'indra/newview')
171 files changed, 3007 insertions, 1631 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 8d685be63e..361718a13e 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1688,7 +1688,7 @@ if (WINDOWS)        # The following commented dependencies are determined at variably at build time. Can't do this here.        ${CMAKE_SOURCE_DIR}/../etc/message.xml        ${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg -      ${SHARED_LIB_STAGING_DIR}/openjpeg.dll +      ${SHARED_LIB_STAGING_DIR}/openjp2.dll        ${SHARED_LIB_STAGING_DIR}/libhunspell.dll        ${SHARED_LIB_STAGING_DIR}/uriparser.dll        #${SHARED_LIB_STAGING_DIR}/${LL_INTDIR}/SLVoice.exe diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index f5199477c5..0673dfa857 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -6.6.9 +6.6.10 diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 6789e71e41..411f77e6a7 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -16887,5 +16887,16 @@      <key>Value</key>      <string></string>    </map> +  <key>DebugSettingsHideDefault</key> +  <map> +    <key>Comment</key> +    <string>Show non-default settings only in Debug Settings list</string> +    <key>Persist</key> +    <integer>0</integer> +    <key>Type</key> +    <string>Boolean</string> +    <key>Value</key> +    <integer>0</integer> +  </map>  </map>  </llsd> diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml index 537744b44c..e89d1cbda4 100644 --- a/indra/newview/app_settings/settings_per_account.xml +++ b/indra/newview/app_settings/settings_per_account.xml @@ -220,6 +220,17 @@          <key>Value</key>              <integer>1</integer>          </map> +    <key>FetchGroupChatHistory</key> +      <map> +        <key>Comment</key> +        <string>Fetch recent messages from group chat servers when a group window opens</string> +        <key>Persist</key> +        <integer>1</integer> +        <key>Type</key> +        <string>Boolean</string> +        <key>Value</key> +        <integer>1</integer> +      </map>      <key>VoiceCallsFriendsOnly</key>      <map>          <key>Comment</key> diff --git a/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl b/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl index 331249dc33..de22312d3c 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl @@ -25,6 +25,17 @@  /*[EXTRA_CODE_HERE]*/ +// Inputs +VARYING vec4 vary_HazeColor; +VARYING float vary_LightNormPosDot; + +uniform sampler2D rainbow_map; +uniform sampler2D halo_map; + +uniform float moisture_level; +uniform float droplet_radius; +uniform float ice_level; +  #ifdef DEFINE_GL_FRAGCOLOR  out vec4 frag_data[3];  #else @@ -35,11 +46,34 @@ out vec4 frag_data[3];  // The fragment shader for the sky  ///////////////////////////////////////////////////////////////////////// -VARYING vec4 vary_HazeColor; +vec3 rainbow(float d) +{ +    // 'Interesting' values of d are -0.75 .. -0.825, i.e. when view vec nearly opposite of sun vec +    // Rainbox tex is mapped with REPEAT, so -.75 as tex coord is same as 0.25.  -0.825 -> 0.175. etc. +    // SL-13629 +    // Unfortunately the texture is inverted, so we need to invert the y coord, but keep the 'interesting' +    // part within the same 0.175..0.250 range, i.e. d = (1 - d) - 1.575 +    d         = clamp(-0.575 - d, 0.0, 1.0); + +    // With the colors in the lower 1/4 of the texture, inverting the coords leaves most of it inaccessible. +    // So, we can stretch the texcoord above the colors (ie > 0.25) to fill the entire remaining coordinate +    // space. This improves gradation, reduces banding within the rainbow interior. (1-0.25) / (0.425/0.25) = 4.2857 +    float interior_coord = max(0.0, d - 0.25) * 4.2857; +    d = clamp(d, 0.0, 0.25) + interior_coord; + +    float rad = (droplet_radius - 5.0f) / 1024.0f; +    return pow(texture2D(rainbow_map, vec2(rad+0.5, d)).rgb, vec3(1.8)) * moisture_level; +} + +vec3 halo22(float d) +{ +    d       = clamp(d, 0.1, 1.0); +    float v = sqrt(clamp(1 - (d * d), 0, 1)); +    return texture2D(halo_map, vec2(0, v)).rgb * ice_level; +}  /// Soft clips the light with a gamma correction  vec3 scaleSoftClip(vec3 light); -vec3 srgb_to_linear(vec3 c);  void main()  { @@ -48,14 +82,18 @@ void main()      // the fragment) if the sky wouldn't show up because the clouds       // are fully opaque. -    vec4 color; -    color = vary_HazeColor; +    vec4 color = vary_HazeColor; +    float  rel_pos_lightnorm = vary_LightNormPosDot; +    float optic_d = rel_pos_lightnorm; +    vec3  halo_22 = halo22(optic_d); +    color.rgb += rainbow(optic_d); +    color.rgb += halo_22;      color.rgb *= 2.;      color.rgb = scaleSoftClip(color.rgb); -    /// Gamma correct for WL (soft clip effect). -    frag_data[0] = vec4(color.rgb, 0.0); +    // Gamma correct for WL (soft clip effect). +    frag_data[0] = vec4(color.rgb, 1.0);      frag_data[1] = vec4(0.0,0.0,0.0,0.0);      frag_data[2] = vec4(0.0,0.0,0.0,1.0); //1.0 in norm.w masks off fog diff --git a/indra/newview/app_settings/shaders/class1/deferred/skyV.glsl b/indra/newview/app_settings/shaders/class1/deferred/skyV.glsl index 28a1faf24f..6db4690bff 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/skyV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/skyV.glsl @@ -33,6 +33,7 @@ ATTRIBUTE vec3 position;  // Output parameters  VARYING vec4 vary_HazeColor; +VARYING float vary_LightNormPosDot;  // Inputs  uniform vec3 camPosLocal; @@ -72,27 +73,29 @@ void main()      vec3 rel_pos = position.xyz - camPosLocal.xyz + vec3(0, 50, 0);      // Adj position vector to clamp altitude -    if (rel_pos.y > 0) +    if (rel_pos.y > 0.)      {          rel_pos *= (max_y / rel_pos.y);      } -    if (rel_pos.y < 0) +    if (rel_pos.y < 0.)      {          rel_pos *= (-32000. / rel_pos.y);      } -    // Can normalize then -    vec3 rel_pos_norm = normalize(rel_pos); +    // Normalized +    vec3  rel_pos_norm = normalize(rel_pos); +    float rel_pos_len  = length(rel_pos); -    float rel_pos_len = length(rel_pos); +    // Grab this value and pass to frag shader for rainbows +    float rel_pos_lightnorm_dot = dot(rel_pos_norm, lightnorm.xyz); +    vary_LightNormPosDot = rel_pos_lightnorm_dot;      // Initialize temp variables      vec4 sunlight = (sun_up_factor == 1) ? sunlight_color : moonlight_color; -    vec4 light_atten;      // Sunlight attenuation effect (hue and brightness) due to atmosphere      // this is used later for sunlight modulation at various altitudes -    light_atten = (blue_density + vec4(haze_density * 0.25)) * (density_multiplier * max_y); +    vec4 light_atten = (blue_density + vec4(haze_density * 0.25)) * (density_multiplier * max_y);      // Calculate relative weights      vec4 combined_haze = abs(blue_density) + vec4(abs(haze_density)); @@ -112,7 +115,7 @@ void main()      combined_haze = exp(-combined_haze * density_dist);      // Compute haze glow -    float haze_glow = 1.0 - dot(rel_pos_norm, lightnorm.xyz); +    float haze_glow = 1.0 - rel_pos_lightnorm_dot;      // haze_glow is 0 at the sun and increases away from sun      haze_glow = max(haze_glow, .001);      // Set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot) @@ -123,30 +126,30 @@ void main()      // Add "minimum anti-solar illumination"      // For sun, add to glow.  For moon, remove glow entirely. SL-13768 -    haze_glow = (sun_moon_glow_factor < 1.0) ? 0.0 : (haze_glow + 0.25); +    haze_glow = (sun_moon_glow_factor < 1.0) ? 0.0 : (sun_moon_glow_factor * (haze_glow + 0.25)); -    vec4 color = -        (blue_horizon * blue_weight * (sunlight + ambient_color) + (haze_horizon * haze_weight) * (sunlight * haze_glow + ambient_color)); +    // Haze color above cloud +    vec4 color = (blue_horizon * blue_weight * (sunlight + ambient_color) +               + (haze_horizon * haze_weight) * (sunlight * haze_glow + ambient_color));      // Final atmosphere additive      color *= (1. - combined_haze);      // Increase ambient when there are more clouds -    vec4 tmpAmbient = ambient_color; -    tmpAmbient += max(vec4(0), (1. - ambient_color)) * cloud_shadow * 0.5; +    vec4 ambient = ambient_color + max(vec4(0), (1. - ambient_color)) * cloud_shadow * 0.5;      // Dim sunlight by cloud shadow percentage      sunlight *= max(0.0, (1. - cloud_shadow));      // Haze color below cloud -    vec4 additiveColorBelowCloud = -        (blue_horizon * blue_weight * (sunlight + tmpAmbient) + (haze_horizon * haze_weight) * (sunlight * haze_glow + tmpAmbient)); +    vec4 add_below_cloud = (blue_horizon * blue_weight * (sunlight + ambient)  +                         + (haze_horizon * haze_weight) * (sunlight * haze_glow + ambient));      // Attenuate cloud color by atmosphere      combined_haze = sqrt(combined_haze);  // less atmos opacity (more transparency) below clouds      // At horizon, blend high altitude sky color towards the darker color below the clouds -    color += (additiveColorBelowCloud - color) * (1. - sqrt(combined_haze)); +    color += (add_below_cloud - color) * (1. - sqrt(combined_haze));      // Haze color above cloud      vary_HazeColor = color; diff --git a/indra/newview/app_settings/shaders/class2/deferred/skyF.glsl b/indra/newview/app_settings/shaders/class2/deferred/skyF.glsl deleted file mode 100644 index 6841a8194f..0000000000 --- a/indra/newview/app_settings/shaders/class2/deferred/skyF.glsl +++ /dev/null @@ -1,199 +0,0 @@ -/** - * @file class2/deferred/skyF.glsl - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2005, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -uniform mat4 modelview_projection_matrix; - -// SKY //////////////////////////////////////////////////////////////////////// -// The vertex shader for creating the atmospheric sky -/////////////////////////////////////////////////////////////////////////////// - -// Inputs -uniform vec3 camPosLocal; - -uniform vec4  lightnorm; -uniform vec4  sunlight_color; -uniform vec4  moonlight_color; -uniform int   sun_up_factor; -uniform vec4  ambient_color; -uniform vec4  blue_horizon; -uniform vec4  blue_density; -uniform float haze_horizon; -uniform float haze_density; - -uniform float cloud_shadow; -uniform float density_multiplier; -uniform float distance_multiplier; -uniform float max_y; - -uniform vec4  glow; -uniform float sun_moon_glow_factor; - -uniform vec4 cloud_color; - -#ifdef DEFINE_GL_FRAGCOLOR -out vec4 frag_data[3]; -#else -#define frag_data gl_FragData -#endif - -VARYING vec3 pos; - -///////////////////////////////////////////////////////////////////////// -// The fragment shader for the sky -///////////////////////////////////////////////////////////////////////// - -uniform sampler2D rainbow_map; -uniform sampler2D halo_map; - -uniform float moisture_level; -uniform float droplet_radius; -uniform float ice_level; - -vec3 rainbow(float d) -{ -    // d is the dot product of view and sun directions, so ranging -1.0..1.0 -    // 'interesting' values of d are the range -0.75..-0.825, when view is nearly opposite of sun vec -    // Rainbox texture mode is GL_REPEAT, so tc of -.75 is equiv to 0.25, -0.825 equiv to 0.175. - -    // SL-13629 Rainbow texture has colors within the correct .175...250 range, but order is inverted. -    // Rather than replace the texture, we mirror and translate the y tc to keep the colors within the -    // interesting range, but in reversed order:  i.e. d = (1 - d) - 1.575 -    d = clamp(-0.575 - d, 0.0, 1.0); - -    // With the colors in the lower 1/4 of the texture, inverting the coords leaves most of it inaccessible. -    // So, we can stretch the texcoord above the colors (ie > 0.25) to fill the entire remaining coordinate -    // space. This improves gradation, reduces banding within the rainbow interior. (1-0.25) / (0.425/0.25) = 4.2857 -    float interior_coord = max(0.0, d - 0.25) * 4.2857; -    d = clamp(d, 0.0, 0.25) + interior_coord; - -    float rad = (droplet_radius - 5.0f) / 1024.0f; -    return pow(texture2D(rainbow_map, vec2(rad, d)).rgb, vec3(1.8)) * moisture_level; -} - -vec3 halo22(float d) -{ -    d       = clamp(d, 0.1, 1.0); -    float v = sqrt(clamp(1 - (d * d), 0, 1)); -    return texture2D(halo_map, vec2(0, v)).rgb * ice_level; -} - -/// Soft clips the light with a gamma correction -vec3 scaleSoftClip(vec3 light); - -void main() -{ -    // World / view / projection -    // Get relative position (offset why?) -    vec3 rel_pos = pos.xyz - camPosLocal.xyz + vec3(0, 50, 0); - -    // Adj position vector to clamp altitude -    if (rel_pos.y > 0.) -    { -        rel_pos *= (max_y / rel_pos.y); -    } -    if (rel_pos.y < 0.) -    { -        rel_pos *= (-32000. / rel_pos.y); -    } - -    // Normalized -    vec3  rel_pos_norm = normalize(rel_pos); -    float rel_pos_len  = length(rel_pos); - -    // Initialize temp variables -    vec4 sunlight = (sun_up_factor == 1) ? sunlight_color : moonlight_color; - -    // Sunlight attenuation effect (hue and brightness) due to atmosphere -    // this is used later for sunlight modulation at various altitudes -    vec4 light_atten = (blue_density + vec4(haze_density * 0.25)) * (density_multiplier * max_y); - -    // Calculate relative weights -    vec4 combined_haze = abs(blue_density) + vec4(abs(haze_density)); -    vec4 blue_weight   = blue_density / combined_haze; -    vec4 haze_weight   = haze_density / combined_haze; - -    // Compute sunlight from rel_pos & lightnorm (for long rays like sky) -    float off_axis = 1.0 / max(1e-6, max(0, rel_pos_norm.y) + lightnorm.y); -    sunlight *= exp(-light_atten * off_axis); - -    // Distance -    float density_dist = rel_pos_len * density_multiplier; - -    // Transparency (-> combined_haze) -    // ATI Bugfix -- can't store combined_haze*density_dist in a variable because the ati -    // compiler gets confused. -    combined_haze = exp(-combined_haze * density_dist); - -    // Compute haze glow -    float haze_glow = dot(rel_pos_norm, lightnorm.xyz); -    haze_glow       = 1. - haze_glow; -    // haze_glow is 0 at the sun and increases away from sun -    haze_glow = max(haze_glow, .001); -    // Set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot) -    haze_glow *= glow.x; -    // Higher glow.x gives dimmer glow (because next step is 1 / "angle") -    haze_glow = pow(haze_glow, glow.z); -    // glow.z should be negative, so we're doing a sort of (1 / "angle") function - -    // Add "minimum anti-solar illumination" -    // For sun, add to glow.  For moon, remove glow entirely. SL-13768 -    haze_glow = (sun_moon_glow_factor < 1.0) ? 0.0 : (sun_moon_glow_factor * (haze_glow + 0.25)); - -    // Haze color above cloud -    vec4 color = blue_horizon * blue_weight * (sunlight + ambient_color)  -               + haze_horizon * haze_weight * (sunlight * haze_glow + ambient_color); - -    // Final atmosphere additive -    color *= (1. - combined_haze); - -    // Increase ambient when there are more clouds -    // TODO 9/20: DJH what does this do?  max(0,(1-ambient)) will change the color -    vec4 ambient = ambient_color + max(vec4(0), (1. - ambient_color)) * cloud_shadow * 0.5; - -    // Dim sunlight by cloud shadow percentage -    sunlight *= max(0.0, (1. - cloud_shadow)); - -    // Haze color below cloud -    vec4 add_below_cloud = blue_horizon * blue_weight * (sunlight + ambient)  -                         + haze_horizon * haze_weight * (sunlight * haze_glow + ambient); - -    // Attenuate cloud color by atmosphere -    combined_haze = sqrt(combined_haze);  // less atmos opacity (more transparency) below clouds - -    // At horizon, blend high altitude sky color towards the darker color below the clouds -    color += (add_below_cloud - color) * (1. - sqrt(combined_haze)); - -    float optic_d = dot(rel_pos_norm, lightnorm.xyz); -    vec3  halo_22 = halo22(optic_d); -    color.rgb += rainbow(optic_d); -    color.rgb += halo_22; -    color.rgb *= 2.; -    color.rgb = scaleSoftClip(color.rgb); - -    // Gamma correct for WL (soft clip effect). -    frag_data[0] = vec4(color.rgb, 1.0); -    frag_data[1] = vec4(0.0, 0.0, 0.0, 0.0); -    frag_data[2] = vec4(0.0, 0.0, 0.0, 1.0);  // 1.0 in norm.w masks off fog -} diff --git a/indra/newview/app_settings/shaders/class2/deferred/skyV.glsl b/indra/newview/app_settings/shaders/class2/deferred/skyV.glsl deleted file mode 100644 index bcf775577a..0000000000 --- a/indra/newview/app_settings/shaders/class2/deferred/skyV.glsl +++ /dev/null @@ -1,42 +0,0 @@ -/**  - * @file WLSkyV.glsl - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2005, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -uniform mat4 modelview_projection_matrix; - -ATTRIBUTE vec3 position; - -// SKY //////////////////////////////////////////////////////////////////////// -// The vertex shader for creating the atmospheric sky -/////////////////////////////////////////////////////////////////////////////// - -VARYING vec3 pos; - -void main() -{ - -	// World / view / projection -    pos = position.xyz; -	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); -} diff --git a/indra/newview/llaccountingcostmanager.cpp b/indra/newview/llaccountingcostmanager.cpp index e09527a34b..d3f988d715 100644 --- a/indra/newview/llaccountingcostmanager.cpp +++ b/indra/newview/llaccountingcostmanager.cpp @@ -96,11 +96,7 @@ void LLAccountingCostManager::accountingCostCoro(std::string url,          LLSD dataToPost = LLSD::emptyMap();          dataToPost[keystr.c_str()] = objectList; -        LLAccountingCostObserver* observer = observerHandle.get(); -        LLUUID transactionId = observer->getTransactionID(); -        observer = NULL; - - +        LLAccountingCostObserver* observer = NULL;          LLSD results = httpAdapter->postAndSuspend(httpRequest, url, dataToPost); diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index 8d2e3905d1..77131efd75 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -133,7 +133,6 @@ LLAgentCamera::LLAgentCamera() :  	mCameraFOVZoomFactor(0.f),  	mCameraCurrentFOVZoomFactor(0.f),  	mCameraFocusOffset(), -	mCameraFOVDefault(DEFAULT_FIELD_OF_VIEW),  	mCameraCollidePlane(), @@ -155,7 +154,6 @@ LLAgentCamera::LLAgentCamera() :  	mFocusObject(NULL),  	mFocusObjectDist(0.f),  	mFocusObjectOffset(), -	mFocusDotRadius( 0.1f ),			// meters  	mTrackFocusObject(TRUE),  	mAtKey(0), // Either 1, 0, or -1... indicates that movement-key is pressed @@ -2361,6 +2359,11 @@ void LLAgentCamera::changeCameraToCustomizeAvatar()  	gAgent.standUp(); // force stand up  	gViewerWindow->getWindow()->resetBusyCount(); +    if (LLSelectMgr::getInstance()->getSelection()->isAttachment()) +    { +        LLSelectMgr::getInstance()->deselectAll(); +    } +  	if (gFaceEditToolset)  	{  		LLToolMgr::getInstance()->setCurrentToolset(gFaceEditToolset); diff --git a/indra/newview/llagentcamera.h b/indra/newview/llagentcamera.h index 89680f95dc..d27cdb0c5c 100644 --- a/indra/newview/llagentcamera.h +++ b/indra/newview/llagentcamera.h @@ -152,7 +152,6 @@ private:  	F32				mTargetCameraDistance;			// Target camera offset from avatar  	F32				mCameraFOVZoomFactor;			// Amount of fov zoom applied to camera when zeroing in on an object  	F32				mCameraCurrentFOVZoomFactor;	// Interpolated fov zoom -	F32				mCameraFOVDefault;				// Default field of view that is basis for FOV zoom effect  	LLVector4		mCameraCollidePlane;			// Colliding plane for camera  	F32				mCameraZoomFraction;			// Mousewheel driven fraction of zoom  	LLVector3		mCameraPositionAgent;			// Camera position in agent coordinates @@ -167,7 +166,6 @@ private:  	// Follow  	//--------------------------------------------------------------------  public: -	void			setUsingFollowCam(bool using_follow_cam);  	bool 			isfollowCamLocked();  private:  	LLFollowCam 	mFollowCam; 			// Ventrella @@ -233,7 +231,6 @@ private:  	LLPointer<LLViewerObject> mFocusObject;  	F32				mFocusObjectDist;  	LLVector3		mFocusObjectOffset; -	F32				mFocusDotRadius; 				// Meters  	BOOL			mTrackFocusObject;  	//-------------------------------------------------------------------- diff --git a/indra/newview/llagentui.cpp b/indra/newview/llagentui.cpp index 3410a37890..c19ad2ae6f 100644 --- a/indra/newview/llagentui.cpp +++ b/indra/newview/llagentui.cpp @@ -53,7 +53,16 @@ void LLAgentUI::buildSLURL(LLSLURL& slurl, const bool escaped /*= true*/)        LLViewerRegion *regionp = gAgent.getRegion();        if (regionp)        { -		  return_slurl = LLSLURL(regionp->getName(), gAgent.getPositionGlobal()); +          // Make sure coordinates are within current region +          LLVector3d global_pos = gAgent.getPositionGlobal(); +          LLVector3d region_origin = regionp->getOriginGlobal(); +          // -1 otherwise slurl will fmod 256 to 0. +          // And valid slurl range is supposed to be 0..255 +          F64 max_val = REGION_WIDTH_METERS - 1; +          global_pos.mdV[VX] = llclamp(global_pos[VX], region_origin[VX], region_origin[VX] + max_val); +          global_pos.mdV[VY] = llclamp(global_pos[VY], region_origin[VY], region_origin[VY] + max_val); + +          return_slurl = LLSLURL(regionp->getName(), global_pos);        }  	slurl = return_slurl;  } diff --git a/indra/newview/llappdelegate-objc.mm b/indra/newview/llappdelegate-objc.mm index 5214f4b838..1090888c1c 100644 --- a/indra/newview/llappdelegate-objc.mm +++ b/indra/newview/llappdelegate-objc.mm @@ -46,6 +46,7 @@  - (void)dealloc  { +    [currentInputLanguage release];      [super dealloc];  } @@ -199,12 +200,14 @@  - (bool) romanScript  { -	// How to add support for new languages with the input window: -	// Simply append this array with the language code (ja for japanese, ko for korean, zh for chinese, etc.) -	NSArray *nonRomanScript = [[NSArray alloc] initWithObjects:@"ja", @"ko", @"zh-Hant", @"zh-Hans", nil]; -	if ([nonRomanScript containsObject:currentInputLanguage]) -    { -        return false; +    @autoreleasepool { +        // How to add support for new languages with the input window: +        // Simply append this array with the language code (ja for japanese, ko for korean, zh for chinese, etc.) +        NSArray* nonRomanScript = @[@"ja", @"ko", @"zh-Hant", @"zh-Hans"]; +        if ([nonRomanScript containsObject:currentInputLanguage]) +        { +            return false; +        }      }      return true; diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 909f32cd21..3c93a9df7e 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -3987,7 +3987,7 @@ void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, boo  		// existence of AIS as an indicator the fix is present. Does  		// not actually use AIS to create the category.  		inventory_func_type func = boost::bind(&LLAppearanceMgr::onOutfitFolderCreated,this,_1,show_panel); -		LLUUID folder_id = gInventory.createNewCategory( +		gInventory.createNewCategory(  			parent_id,  			LLFolderType::FT_OUTFIT,  			new_folder_name, diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 4ba3190fa8..9e06fc3ac0 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -135,6 +135,10 @@  #include "vlc/libvlc_version.h"  #endif // LL_LINUX +#if LL_DARWIN +#include "llwindowmacosx.h" +#endif +  // Third party library includes  #include <boost/bind.hpp>  #include <boost/foreach.hpp> @@ -560,6 +564,7 @@ static void settings_to_globals()      LLWorldMapView::setScaleSetting(gSavedSettings.getF32("MapScale"));  #if LL_DARWIN +    LLWindowMacOSX::sUseMultGL = gSavedSettings.getBOOL("RenderAppleUseMultGL");  	gHiDPISupport = gSavedSettings.getBOOL("RenderHiDPI");  #endif  } @@ -1719,7 +1724,8 @@ bool LLAppViewer::cleanup()  	{  		if (!isSecondInstance())  		{ -			LLSceneMonitor::instance().dumpToFile(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "scene_monitor_results.csv")); +            std::string dump_path = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "scene_monitor_results.csv"); +			LLSceneMonitor::instance().dumpToFile(dump_path);  		}  		LLSceneMonitor::deleteSingleton();  	} @@ -5469,7 +5475,8 @@ void LLAppViewer::disconnectViewer()      {          gInventory.cache(gInventory.getRootFolderID(), gAgent.getID());          if (gInventory.getLibraryRootFolderID().notNull() -            && gInventory.getLibraryOwnerID().notNull()) +            && gInventory.getLibraryOwnerID().notNull() +            && !mSecondInstance) // agent is unique, library isn't          {              gInventory.cache(                  gInventory.getLibraryRootFolderID(), diff --git a/indra/newview/llavatarrenderinfoaccountant.cpp b/indra/newview/llavatarrenderinfoaccountant.cpp index 275f17b02a..293c9d60a1 100644 --- a/indra/newview/llavatarrenderinfoaccountant.cpp +++ b/indra/newview/llavatarrenderinfoaccountant.cpp @@ -364,11 +364,10 @@ void LLAvatarRenderInfoAccountant::getRenderInfoFromRegion(LLViewerRegion * regi  	}  } -// static  // Called every frame - send render weight requests to every region  void LLAvatarRenderInfoAccountant::idle()  { -	if (mRenderInfoScanTimer.hasExpired()) +	if (mRenderInfoScanTimer.hasExpired() && !LLApp::isExiting())  	{  		LL_DEBUGS("AvatarRenderInfo") << "Scanning regions for render info updates"  									  << LL_ENDL; diff --git a/indra/newview/llbuycurrencyhtml.cpp b/indra/newview/llbuycurrencyhtml.cpp index 1c69dadb12..7ad06f8eaa 100644 --- a/indra/newview/llbuycurrencyhtml.cpp +++ b/indra/newview/llbuycurrencyhtml.cpp @@ -41,7 +41,7 @@ class LLBuyCurrencyHTMLHandler :  {  public:  	// requests will be throttled from a non-trusted browser -	LLBuyCurrencyHTMLHandler() : LLCommandHandler( "buycurrencyhtml", UNTRUSTED_ALLOW ) {} +	LLBuyCurrencyHTMLHandler() : LLCommandHandler( "buycurrencyhtml", UNTRUSTED_THROTTLE) {}  	bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)  	{ diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp index 1ad2157df0..df79043b00 100644 --- a/indra/newview/llcallingcard.cpp +++ b/indra/newview/llcallingcard.cpp @@ -650,8 +650,7 @@ void LLAvatarTracker::processChange(LLMessageSystem* msg)  		{  			if(mBuddyInfo.find(agent_id) != mBuddyInfo.end())  			{ -                if (((mBuddyInfo[agent_id]->getRightsGrantedFrom() ^  new_rights) & LLRelationship::GRANT_MODIFY_OBJECTS) -                    && !gAgent.isDoNotDisturb()) +                if (((mBuddyInfo[agent_id]->getRightsGrantedFrom() ^  new_rights) & LLRelationship::GRANT_MODIFY_OBJECTS))  				{  					LLSD args;  					args["NAME"] = LLSLURL("agent", agent_id, "displayname").getSLURLString(); @@ -719,11 +718,12 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online)  				// we were tracking someone who went offline  				deleteTrackingData();  			} -		} -		if(chat_notify) -		{ -			// Look up the name of this agent for the notification -			LLAvatarNameCache::get(agent_id,boost::bind(&on_avatar_name_cache_notify,_1, _2, online, payload)); + +            if(chat_notify) +            { +                // Look up the name of this agent for the notification +                LLAvatarNameCache::get(agent_id,boost::bind(&on_avatar_name_cache_notify,_1, _2, online, payload)); +            }  		}  		mModifyMask |= LLFriendObserver::ONLINE; diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 7188b9136c..9a608fba8e 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -141,6 +141,18 @@ public:  		{  			mAvatarNameCacheConnection.disconnect();  		} +		auto menu = mPopupMenuHandleAvatar.get(); +		if (menu) +		{ +			menu->die(); +			mPopupMenuHandleAvatar.markDead(); +		} +		menu = mPopupMenuHandleObject.get(); +		if (menu) +		{ +			menu->die(); +			mPopupMenuHandleObject.markDead(); +		}  	}  	BOOL handleMouseUp(S32 x, S32 y, MASK mask) @@ -567,36 +579,6 @@ public:  	BOOL postBuild()  	{ -		LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; -		LLUICtrl::EnableCallbackRegistry::ScopedRegistrar registrar_enable; - -		registrar.add("AvatarIcon.Action", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemClicked, this, _2)); -		registrar_enable.add("AvatarIcon.Check", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemChecked, this, _2)); -		registrar_enable.add("AvatarIcon.Enable", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemEnabled, this, _2)); -		registrar_enable.add("AvatarIcon.Visible", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemVisible, this, _2)); -		registrar.add("ObjectIcon.Action", boost::bind(&LLChatHistoryHeader::onObjectIconContextMenuItemClicked, this, _2)); -		registrar_enable.add("ObjectIcon.Visible", boost::bind(&LLChatHistoryHeader::onObjectIconContextMenuItemVisible, this, _2)); - -		LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_avatar_icon.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); -		if (menu) -		{ -			mPopupMenuHandleAvatar = menu->getHandle(); -		} -		else -		{ -			LL_WARNS() << " Failed to create menu_avatar_icon.xml" << LL_ENDL; -		} - -		menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_object_icon.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); -		if (menu) -		{ -			mPopupMenuHandleObject = menu->getHandle(); -		} -		else -		{ -			LL_WARNS() << " Failed to create menu_object_icon.xml" << LL_ENDL; -		} -  		setDoubleClickCallback(boost::bind(&LLChatHistoryHeader::showInspector, this));  		setMouseEnterCallback(boost::bind(&LLChatHistoryHeader::showInfoCtrl, this)); @@ -884,13 +866,53 @@ protected:  	void showObjectContextMenu(S32 x,S32 y)  	{  		LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandleObject.get(); -		if(menu) +		if (!menu) +		{ +			LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; +			LLUICtrl::EnableCallbackRegistry::ScopedRegistrar registrar_enable; +			registrar.add("ObjectIcon.Action", boost::bind(&LLChatHistoryHeader::onObjectIconContextMenuItemClicked, this, _2)); +			registrar_enable.add("ObjectIcon.Visible", boost::bind(&LLChatHistoryHeader::onObjectIconContextMenuItemVisible, this, _2)); + +			menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_object_icon.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); +			if (menu) +			{ +				mPopupMenuHandleObject = menu->getHandle(); +				menu->updateParent(LLMenuGL::sMenuContainer); +				LLMenuGL::showPopup(this, menu, x, y); +			} +			else +			{ +				LL_WARNS() << " Failed to create menu_object_icon.xml" << LL_ENDL; +			} +		} +		else +		{  			LLMenuGL::showPopup(this, menu, x, y); +		}  	}  	void showAvatarContextMenu(S32 x,S32 y)  	{  		LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandleAvatar.get(); +		if (!menu) +		{ +			LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; +			LLUICtrl::EnableCallbackRegistry::ScopedRegistrar registrar_enable; +			registrar.add("AvatarIcon.Action", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemClicked, this, _2)); +			registrar_enable.add("AvatarIcon.Check", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemChecked, this, _2)); +			registrar_enable.add("AvatarIcon.Enable", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemEnabled, this, _2)); +			registrar_enable.add("AvatarIcon.Visible", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemVisible, this, _2)); + +			menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_avatar_icon.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); +			if (menu) +			{ +				mPopupMenuHandleAvatar = menu->getHandle(); +			} +			else +			{ +				LL_WARNS() << " Failed to create menu_avatar_icon.xml" << LL_ENDL; +			} +		}  		if(menu)  		{ @@ -1082,10 +1104,7 @@ LLChatHistory::LLChatHistory(const LLChatHistory::Params& p)  LLSD LLChatHistory::getValue() const  { -  LLSD* text=new LLSD();  -  text->assign(mEditor->getText()); -  return *text; -     +	return LLSD(mEditor->getText());  }  LLChatHistory::~LLChatHistory() diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index 0f187b0ecf..cc4f4536a4 100644 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -67,7 +67,6 @@ LLSysWellChiclet::LLSysWellChiclet(const Params& p)  	, mMaxDisplayedCount(p.max_displayed_count)  	, mIsNewMessagesState(false)  	, mFlashToLitTimer(NULL) -	, mContextMenu(NULL)  {  	LLButton::Params button_params = p.button;  	mButton = LLUICtrlFactory::create<LLButton>(button_params); @@ -79,6 +78,12 @@ LLSysWellChiclet::LLSysWellChiclet(const Params& p)  LLSysWellChiclet::~LLSysWellChiclet()  {  	mFlashToLitTimer->unset(); +	LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get()); +	if (menu) +	{ +		menu->die(); +		mContextMenuHandle.markDead(); +	}  }  void LLSysWellChiclet::setCounter(S32 counter) @@ -145,14 +150,16 @@ void LLSysWellChiclet::updateWidget(bool is_window_empty)  // virtual  BOOL LLSysWellChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask)  { -	if(!mContextMenu) +	LLContextMenu* menu_avatar = mContextMenuHandle.get(); +	if(!menu_avatar)  	{  		createMenu(); +		menu_avatar = mContextMenuHandle.get();  	} -	if (mContextMenu) +	if (menu_avatar)  	{ -		mContextMenu->show(x, y); -		LLMenuGL::showPopup(this, mContextMenu, x, y); +		menu_avatar->show(x, y); +		LLMenuGL::showPopup(this, menu_avatar, x, y);  	}  	return TRUE;  } @@ -192,7 +199,7 @@ bool LLNotificationChiclet::enableMenuItem(const LLSD& user_data)  void LLNotificationChiclet::createMenu()  { -	if(mContextMenu) +	if(mContextMenuHandle.get())  	{  		LL_WARNS() << "Menu already exists" << LL_ENDL;  		return; @@ -207,10 +214,14 @@ void LLNotificationChiclet::createMenu()  		boost::bind(&LLNotificationChiclet::enableMenuItem, this, _2));  	llassert(LLMenuGL::sMenuContainer != NULL); -	mContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu> +	LLContextMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>  		("menu_notification_well_button.xml",  		 LLMenuGL::sMenuContainer,  		 LLViewerMenuHolderGL::child_registry_t::instance()); +	if (menu) +	{ +		mContextMenuHandle = menu->getHandle(); +	}  }  /*virtual*/ @@ -309,10 +320,19 @@ LLIMChiclet::LLIMChiclet(const LLIMChiclet::Params& p)  , mDefaultWidth(p.rect().getWidth())  , mNewMessagesIcon(NULL)  , mChicletButton(NULL) -, mPopupMenu(NULL)  {  } +LLIMChiclet::~LLIMChiclet() +{ +	auto menu = mPopupMenuHandle.get(); +	if (menu) +	{ +		menu->die(); +		mPopupMenuHandle.markDead(); +	} +} +  /* virtual*/  BOOL LLIMChiclet::postBuild()  { @@ -364,16 +384,18 @@ void LLIMChiclet::setToggleState(bool toggle)  BOOL LLIMChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask)  { -	if(!mPopupMenu) +	auto menu = static_cast<LLMenuGL*>(mPopupMenuHandle.get()); +	if(!menu)  	{  		createPopupMenu(); +		menu = static_cast<LLMenuGL*>(mPopupMenuHandle.get());  	} -	if (mPopupMenu) +	if (menu)  	{  		updateMenuItems(); -		mPopupMenu->arrangeAndClear(); -		LLMenuGL::showPopup(this, mPopupMenu, x, y); +		menu->arrangeAndClear(); +		LLMenuGL::showPopup(this, menu, x, y);  	}  	return TRUE; @@ -381,15 +403,16 @@ BOOL LLIMChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask)  void LLIMChiclet::hidePopupMenu()  { -	if (mPopupMenu) +	auto menu = mPopupMenuHandle.get(); +	if (menu)  	{ -		mPopupMenu->setVisible(FALSE); +		menu->setVisible(FALSE);  	}  }  bool LLIMChiclet::canCreateMenu()  { -	if(mPopupMenu) +	if(mPopupMenuHandle.get())  	{  		LL_WARNS() << "Menu already exists" << LL_ENDL;  		return false; @@ -1107,8 +1130,13 @@ void LLScriptChiclet::createPopupMenu()  	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;  	registrar.add("ScriptChiclet.Action", boost::bind(&LLScriptChiclet::onMenuItemClicked, this, _2)); -	mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL> +	LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>  		("menu_script_chiclet.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); +	if (menu) +	{ +		mPopupMenuHandle = menu->getHandle(); +	} +  }  ////////////////////////////////////////////////////////////////////////// @@ -1185,8 +1213,12 @@ void LLInvOfferChiclet::createPopupMenu()  	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;  	registrar.add("InvOfferChiclet.Action", boost::bind(&LLInvOfferChiclet::onMenuItemClicked, this, _2)); -	mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL> +	LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>  		("menu_inv_offer_chiclet.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); +	if (menu) +	{ +		mPopupMenuHandle = menu->getHandle(); +	}  }  // EOF diff --git a/indra/newview/llchiclet.h b/indra/newview/llchiclet.h index aceedda07e..58a797218f 100644 --- a/indra/newview/llchiclet.h +++ b/indra/newview/llchiclet.h @@ -252,7 +252,7 @@ public:  	{}; -	virtual ~LLIMChiclet() {}; +	virtual ~LLIMChiclet();  	/**  	 * It is used for default setting up of chicklet:click handler, etc.   @@ -325,7 +325,7 @@ protected:  	bool canCreateMenu(); -	LLMenuGL* mPopupMenu; +	LLHandle<LLUICtrl> mPopupMenuHandle;  	bool mShowSpeaker;  	bool mCounterEnabled; @@ -519,7 +519,7 @@ protected:  	bool mIsNewMessagesState;  	LLFlashTimer* mFlashToLitTimer; -	LLContextMenu* mContextMenu; +	LLHandle<LLContextMenu> mContextMenuHandle;  };  class LLNotificationChiclet : public LLSysWellChiclet diff --git a/indra/newview/llcommandhandler.cpp b/indra/newview/llcommandhandler.cpp index 23e2271eae..74f37961c7 100644 --- a/indra/newview/llcommandhandler.cpp +++ b/indra/newview/llcommandhandler.cpp @@ -39,6 +39,7 @@  #define THROTTLE_PERIOD    5    // required seconds between throttled commands  static LLCommandDispatcherListener sCommandDispatcherListener; +const std::string LLCommandHandler::NAV_TYPE_CLICKED = "clicked";  //---------------------------------------------------------------------------  // Underlying registry for command handlers, not directly accessible. @@ -64,6 +65,9 @@ public:  				  bool trusted_browser);  private: +    void notifySlurlBlocked(); +    void notifySlurlThrottled(); +  	friend LLSD LLCommandDispatcher::enumerate();  	std::map<std::string, LLCommandHandlerInfo> mMap;  }; @@ -96,8 +100,6 @@ bool LLCommandHandlerRegistry::dispatch(const std::string& cmd,  										const std::string& nav_type,  										bool trusted_browser)  { -	static bool slurl_blocked = false; -	static bool slurl_throttled = false;  	static F64 last_throttle_time = 0.0;  	F64 cur_time = 0.0;  	std::map<std::string, LLCommandHandlerInfo>::iterator it = mMap.find(cmd); @@ -115,44 +117,45 @@ bool LLCommandHandlerRegistry::dispatch(const std::string& cmd,  			// block request from external browser, but report as  			// "handled" because it was well formatted.  			LL_WARNS_ONCE("SLURL") << "Blocked SLURL command from untrusted browser" << LL_ENDL; -			if (! slurl_blocked) -			{ -				if (LLStartUp::getStartupState() >= STATE_BROWSER_INIT) -				{ -					// Note: commands can arrive before we initialize everything we need for Notification. -					LLNotificationsUtil::add("BlockedSLURL"); -				} -				slurl_blocked = true; -			} +            notifySlurlBlocked();  			return true; +        case LLCommandHandler::UNTRUSTED_CLICK_ONLY: +            if (nav_type == LLCommandHandler::NAV_TYPE_CLICKED +                && info.mHandler->canHandleUntrusted(params, query_map, web, nav_type)) +            { +                break; +            } +            LL_WARNS_ONCE("SLURL") << "Blocked SLURL click-only command " << cmd << " from untrusted browser" << LL_ENDL; +            notifySlurlBlocked(); +            return true; +  		case LLCommandHandler::UNTRUSTED_THROTTLE: +			//skip initial request from external browser before STATE_BROWSER_INIT +			if (LLStartUp::getStartupState() == STATE_FIRST) +			{ +				return true; +			} +            if (!info.mHandler->canHandleUntrusted(params, query_map, web, nav_type)) +            { +                LL_WARNS_ONCE("SLURL") << "Blocked SLURL command from untrusted browser" << LL_ENDL; +                notifySlurlBlocked(); +                return true; +            }  			// if users actually click on a link, we don't need to throttle it  			// (throttling mechanism is used to prevent an avalanche of clicks via  			// javascript -			if ( nav_type == "clicked" ) +			if (nav_type == LLCommandHandler::NAV_TYPE_CLICKED)  			{  				break;  			} -			//skip initial request from external browser before STATE_BROWSER_INIT -			if (LLStartUp::getStartupState() == STATE_FIRST) -			{ -				return true; -			}  			cur_time = LLTimer::getElapsedSeconds();  			if (cur_time < last_throttle_time + THROTTLE_PERIOD)  			{  				// block request from external browser if it happened  				// within THROTTLE_PERIOD seconds of the last command  				LL_WARNS_ONCE("SLURL") << "Throttled SLURL command from untrusted browser" << LL_ENDL; -				if (! slurl_throttled) -				{ -					if (LLStartUp::getStartupState() >= STATE_BROWSER_INIT) -					{ -						LLNotificationsUtil::add("ThrottledSLURL"); -					} -					slurl_throttled = true; -				} +                notifySlurlThrottled();  				return true;  			}  			last_throttle_time = cur_time; @@ -163,6 +166,34 @@ bool LLCommandHandlerRegistry::dispatch(const std::string& cmd,  	return info.mHandler->handle(params, query_map, web);  } +void LLCommandHandlerRegistry::notifySlurlBlocked() +{ +    static bool slurl_blocked = false; +    if (!slurl_blocked) +    { +        if (LLStartUp::getStartupState() >= STATE_BROWSER_INIT) +        { +            // Note: commands can arrive before we initialize everything we need for Notification. +            LLNotificationsUtil::add("BlockedSLURL"); +        } +        slurl_blocked = true; +    } +} + +void LLCommandHandlerRegistry::notifySlurlThrottled() +{ +    static bool slurl_throttled = false; +    if (!slurl_throttled) +    { +        if (LLStartUp::getStartupState() >= STATE_BROWSER_INIT) +        { +            // Note: commands can arrive before we initialize everything we need for Notification. +            LLNotificationsUtil::add("ThrottledSLURL"); +        } +        slurl_throttled = true; +    } +} +  //---------------------------------------------------------------------------  // Automatic registration of commands, runs before main()  //--------------------------------------------------------------------------- @@ -230,6 +261,7 @@ symbol_info symbols[] =  {  	ent(LLCommandHandler::UNTRUSTED_ALLOW),		  // allow commands from untrusted browsers  	ent(LLCommandHandler::UNTRUSTED_BLOCK),		  // ignore commands from untrusted browsers +    ent(LLCommandHandler::UNTRUSTED_CLICK_ONLY),  // allow untrusted, but only if clicked  	ent(LLCommandHandler::UNTRUSTED_THROTTLE)	  // allow untrusted, but only a few per min.  }; diff --git a/indra/newview/llcommandhandler.h b/indra/newview/llcommandhandler.h index 1e0895565a..763e3ee51f 100644 --- a/indra/newview/llcommandhandler.h +++ b/indra/newview/llcommandhandler.h @@ -65,9 +65,12 @@ public:  	{  		UNTRUSTED_ALLOW,       // allow commands from untrusted browsers  		UNTRUSTED_BLOCK,       // ignore commands from untrusted browsers +        UNTRUSTED_CLICK_ONLY,  // allow untrusted, but only if clicked  		UNTRUSTED_THROTTLE     // allow untrusted, but only a few per min.  	}; +    static const std::string NAV_TYPE_CLICKED; +  	LLCommandHandler(const char* command, EUntrustedAccess untrusted_access);  		// Automatically registers object to get called when   		// command is executed.  All commands can be processed @@ -76,6 +79,13 @@ public:  	virtual ~LLCommandHandler(); +    virtual bool canHandleUntrusted( +        const LLSD& params, +        const LLSD& query_map, +        LLMediaCtrl* web, +        const std::string& nav_type) +    { return true; } +  	virtual bool handle(const LLSD& params,  						const LLSD& query_map,  						LLMediaCtrl* web) = 0; diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index c4c88d304c..e6b6b10408 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -78,7 +78,9 @@ static S32 cube_channel = -1;  static S32 diffuse_channel = -1;  static S32 bump_channel = -1; -#define LL_BUMPLIST_MULTITHREADED 0 // TODO -- figure out why this doesn't work +// Enabled after changing LLViewerTexture::mNeedsCreateTexture to an +// LLAtomicBool; this should work just fine, now. HB +#define LL_BUMPLIST_MULTITHREADED 1  // static  diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp index 4ef14c20f7..05c7decfbd 100644 --- a/indra/newview/llenvironment.cpp +++ b/indra/newview/llenvironment.cpp @@ -684,7 +684,6 @@ namespace              if (!injection->mBlendIn)                  mix = 1.0 - mix;              stringset_t dummy; -            LLUUID cloud_noise_id = getCloudNoiseTextureId();              F64 value = this->mSettings[injection->mKeyName].asReal();              if (this->getCloudNoiseTextureId().isNull())              { @@ -3097,7 +3096,7 @@ bool LLEnvironment::loadFromSettings()          LL_INFOS("ENVIRONMENT") << "Unable to open previous session environment file " << user_filepath << LL_ENDL;      } -    if (!env_data.isMap() || env_data.emptyMap()) +    if (!env_data.isMap() || (env_data.size() == 0))      {          LL_DEBUGS("ENVIRONMENT") << "Empty map loaded from: " << user_filepath << LL_ENDL;          return false; diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 5a4c8619c7..b5f6f80b39 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -586,9 +586,9 @@ BOOL LLFilePicker::getSaveFile(ESaveFilter filter, const std::string& filename,  #elif LL_DARWIN -std::vector<std::string>* LLFilePicker::navOpenFilterProc(ELoadFilter filter) //(AEDesc *theItem, void *info, void *callBackUD, NavFilterModes filterMode) +std::unique_ptr<std::vector<std::string>> LLFilePicker::navOpenFilterProc(ELoadFilter filter) //(AEDesc *theItem, void *info, void *callBackUD, NavFilterModes filterMode)  { -    std::vector<std::string> *allowedv = new std::vector< std::string >; +    std::unique_ptr<std::vector<std::string>> allowedv(new std::vector< std::string >);      switch(filter)      {          case FFLOAD_ALL: @@ -661,9 +661,9 @@ bool	LLFilePicker::doNavChooseDialog(ELoadFilter filter)  	gViewerWindow->getWindow()->beforeDialog(); -    std::vector<std::string> *allowed_types=navOpenFilterProc(filter); +    std::unique_ptr<std::vector<std::string>> allowed_types = navOpenFilterProc(filter); -    std::vector<std::string> *filev  = doLoadDialog(allowed_types,  +    std::unique_ptr<std::vector<std::string>> filev  = doLoadDialog(allowed_types.get(),                                                      mPickOptions);  	gViewerWindow->getWindow()->afterDialog(); @@ -780,7 +780,7 @@ bool	LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& filena  	gViewerWindow->getWindow()->beforeDialog();  	// Run the dialog -    std::string* filev = doSaveDialog(&namestring,  +    std::unique_ptr<std::string> filev = doSaveDialog(&namestring,                    &type,                   &creator,                   &extension, diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h index 04ba4416d7..73baeca1c0 100644 --- a/indra/newview/llfilepicker.h +++ b/indra/newview/llfilepicker.h @@ -167,7 +167,7 @@ private:  	bool doNavChooseDialog(ELoadFilter filter);  	bool doNavSaveDialog(ESaveFilter filter, const std::string& filename); -    std::vector<std::string>* navOpenFilterProc(ELoadFilter filter); +    std::unique_ptr<std::vector<std::string>> navOpenFilterProc(ELoadFilter filter);  #endif  #if LL_GTK diff --git a/indra/newview/llfilepicker_mac.h b/indra/newview/llfilepicker_mac.h index e0b7e2e8ce..b2fb371afe 100644 --- a/indra/newview/llfilepicker_mac.h +++ b/indra/newview/llfilepicker_mac.h @@ -39,9 +39,9 @@  #include <vector>  //void modelessPicker(); -std::vector<std::string>* doLoadDialog(const std::vector<std::string>* allowed_types,  +std::unique_ptr<std::vector<std::string>> doLoadDialog(const std::vector<std::string>* allowed_types,                   unsigned int flags); -std::string* doSaveDialog(const std::string* file,  +std::unique_ptr<std::string> doSaveDialog(const std::string* file,                     const std::string* type,                    const std::string* creator,                    const std::string* extension, diff --git a/indra/newview/llfilepicker_mac.mm b/indra/newview/llfilepicker_mac.mm index 1438e4dc0a..0ae5fc3f77 100644 --- a/indra/newview/llfilepicker_mac.mm +++ b/indra/newview/llfilepicker_mac.mm @@ -29,104 +29,107 @@  #include <iostream>  #include "llfilepicker_mac.h" -std::vector<std::string>* doLoadDialog(const std::vector<std::string>* allowed_types,  +std::unique_ptr<std::vector<std::string>> doLoadDialog(const std::vector<std::string>* allowed_types,                   unsigned int flags)  { -    int i, result; -     -    //Aura TODO:  We could init a small window and release it at the end of this routine -    //for a modeless interface. -     -    NSOpenPanel *panel = [NSOpenPanel openPanel]; -    //NSString *fileName = nil; -    NSMutableArray *fileTypes = nil; -     -     -    if ( allowed_types && !allowed_types->empty())  -    { -        fileTypes = [[NSMutableArray alloc] init]; +    std::unique_ptr<std::vector<std::string>> outfiles; + +    @autoreleasepool { +        int i, result; +        //Aura TODO:  We could init a small window and release it at the end of this routine +        //for a modeless interface. +         +        NSOpenPanel *panel = [NSOpenPanel openPanel]; +        //NSString *fileName = nil; +        NSMutableArray *fileTypes = nil; -        for (i=0;i<allowed_types->size();++i) +        if ( allowed_types && !allowed_types->empty())          { -            [fileTypes addObject:  -             [NSString stringWithCString:(*allowed_types)[i].c_str()  -                                encoding:[NSString defaultCStringEncoding]]]; +            fileTypes = [[[NSMutableArray alloc] init] autorelease]; +             +            for (i=0;i<allowed_types->size();++i) +            { +                [fileTypes addObject: +                 [NSString stringWithCString:(*allowed_types)[i].c_str() +                                    encoding:[NSString defaultCStringEncoding]]]; +            }          } -    } -    //[panel setMessage:@"Import one or more files or directories."]; -    [panel setAllowsMultipleSelection: ( (flags & F_MULTIPLE)?true:false ) ]; -    [panel setCanChooseDirectories: ( (flags & F_DIRECTORY)?true:false ) ]; -    [panel setCanCreateDirectories: true]; -    [panel setResolvesAliases: true]; -    [panel setCanChooseFiles: ( (flags & F_FILE)?true:false )]; -    [panel setTreatsFilePackagesAsDirectories: ( flags & F_NAV_SUPPORT ) ]; -     -    std::vector<std::string>* outfiles = NULL;  -     -    if (fileTypes) -    { -        [panel setAllowedFileTypes:fileTypes]; -        result = [panel runModal]; -    } -    else  -    { -        // I suggest it's better to open the last path and let this default to home dir as necessary -        // for consistency with other OS X apps -        // -        //[panel setDirectoryURL: fileURLWithPath(NSHomeDirectory()) ]; -        result = [panel runModal]; -    } -     -    if (result == NSOKButton)  -    { -        NSArray *filesToOpen = [panel URLs]; -        int i, count = [filesToOpen count]; +        //[panel setMessage:@"Import one or more files or directories."]; +        [panel setAllowsMultipleSelection: ( (flags & F_MULTIPLE)?true:false ) ]; +        [panel setCanChooseDirectories: ( (flags & F_DIRECTORY)?true:false ) ]; +        [panel setCanCreateDirectories: true]; +        [panel setResolvesAliases: true]; +        [panel setCanChooseFiles: ( (flags & F_FILE)?true:false )]; +        [panel setTreatsFilePackagesAsDirectories: ( flags & F_NAV_SUPPORT ) ]; -        if (count > 0) +        if (fileTypes) +        { +            [panel setAllowedFileTypes:fileTypes]; +            result = [panel runModal]; +        } +        else          { -            outfiles = new std::vector<std::string>; +            // I suggest it's better to open the last path and let this default to home dir as necessary +            // for consistency with other OS X apps +            // +            //[panel setDirectoryURL: fileURLWithPath(NSHomeDirectory()) ]; +            result = [panel runModal];          } -        for (i=0; i<count; i++) { -            NSString *aFile = [[filesToOpen objectAtIndex:i] path]; -            std::string *afilestr = new std::string([aFile UTF8String]); -            outfiles->push_back(*afilestr); +        if (result == NSOKButton) +        { +            NSArray *filesToOpen = [panel URLs]; +            int i, count = [filesToOpen count]; +             +            if (count > 0) +            { +                outfiles.reset(new std::vector<std::string>); +            } +             +            for (i=0; i<count; i++) { +                NSString *aFile = [[filesToOpen objectAtIndex:i] path]; +                std::string afilestr = std::string([aFile UTF8String]); +                outfiles->push_back(afilestr); +            }          }      } +      return outfiles;  } -std::string* doSaveDialog(const std::string* file,  +std::unique_ptr<std::string> doSaveDialog(const std::string* file,                    const std::string* type,                    const std::string* creator,                    const std::string* extension,                    unsigned int flags)  { -    NSSavePanel *panel = [NSSavePanel savePanel];  -     -    NSString *extensionns = [NSString stringWithCString:extension->c_str() encoding:[NSString defaultCStringEncoding]]; -    NSArray *fileType = [extensionns componentsSeparatedByString:@","]; -     -    //[panel setMessage:@"Save Image File"];  -    [panel setTreatsFilePackagesAsDirectories: ( flags & F_NAV_SUPPORT ) ]; -    [panel setCanSelectHiddenExtension:true];  -    [panel setAllowedFileTypes:fileType]; -    NSString *fileName = [NSString stringWithCString:file->c_str() encoding:[NSString defaultCStringEncoding]]; -     -    std::string *outfile = NULL; -    NSURL* url = [NSURL fileURLWithPath:fileName]; -    [panel setNameFieldStringValue: fileName]; -    [panel setDirectoryURL: url]; -    if([panel runModal] ==  -       NSFileHandlingPanelOKButton)  -    { -        NSURL* url = [panel URL]; -        NSString* p = [url path]; -        outfile = new std::string( [p UTF8String] ); -        // write the file  -    }  +    std::unique_ptr<std::string> outfile; +    @autoreleasepool { +        NSSavePanel *panel = [NSSavePanel savePanel]; +         +        NSString *extensionns = [NSString stringWithCString:extension->c_str() encoding:[NSString defaultCStringEncoding]]; +        NSArray *fileType = [extensionns componentsSeparatedByString:@","]; +         +        //[panel setMessage:@"Save Image File"]; +        [panel setTreatsFilePackagesAsDirectories: ( flags & F_NAV_SUPPORT ) ]; +        [panel setCanSelectHiddenExtension:true]; +        [panel setAllowedFileTypes:fileType]; +        NSString *fileName = [NSString stringWithCString:file->c_str() encoding:[NSString defaultCStringEncoding]]; +         +        NSURL* url = [NSURL fileURLWithPath:fileName]; +        [panel setNameFieldStringValue: fileName]; +        [panel setDirectoryURL: url]; +        if([panel runModal] == +           NSFileHandlingPanelOKButton) +        { +            NSURL* url = [panel URL]; +            NSString* p = [url path]; +            outfile.reset(new std::string([p UTF8String])); +            // write the file +        } +    }      return outfile;  } diff --git a/indra/newview/llfloater360capture.cpp b/indra/newview/llfloater360capture.cpp index 85366be402..542a1ea39b 100644 --- a/indra/newview/llfloater360capture.cpp +++ b/indra/newview/llfloater360capture.cpp @@ -537,7 +537,8 @@ void LLFloater360Capture::capture360Images()      // We need to convert from the angle getYaw() gives us into something      // the XMP data field wants (N=0, E=90, S=180, W= 270 etc.)      mInitialHeadingDeg  = (360 + 90 - (int)(camera->getYaw() * RAD_TO_DEG)) % 360; -    LL_INFOS("360Capture") << "Recording a heading of " << (int)(mInitialHeadingDeg) << LL_ENDL; +    LL_INFOS("360Capture") << "Recording a heading of " << (int)(mInitialHeadingDeg) +        << " Image size: " << (S32)mSourceImageSize << LL_ENDL;      // camera constants for the square, cube map capture image      camera->setAspect(1.0); // must set aspect ratio first to avoid undesirable clamping of vertical FoV @@ -587,6 +588,9 @@ void LLFloater360Capture::capture360Images()      // for each of the 6 directions we shoot...      for (int i = 0; i < 6; i++)      { +        LLAppViewer::instance()->pauseMainloopTimeout(); +        LLViewerStats::instance().getRecording().stop(); +          // these buffers are where the raw, captured pixels are stored and          // the first time we use them, we have to make a new one          if (mRawImages[i] == nullptr) @@ -624,8 +628,10 @@ void LLFloater360Capture::capture360Images()          auto duration = std::chrono::duration_cast<std::chrono::duration<double>>(t_end - t_start);          encode_time_total += duration.count(); -        // ping the main loop in case the snapshot process takes a really long -        // time and we get disconnected +        LLViewerStats::instance().getRecording().resume(); +        LLAppViewer::instance()->resumeMainloopTimeout(); +         +        // update main loop timeout state          LLAppViewer::instance()->pingMainloopTimeout("LLFloater360Capture::capture360Images");      } diff --git a/indra/newview/llfloateravatar.cpp b/indra/newview/llfloateravatar.cpp index 31adf5b61e..f888d032ae 100644 --- a/indra/newview/llfloateravatar.cpp +++ b/indra/newview/llfloateravatar.cpp @@ -44,17 +44,21 @@ LLFloaterAvatar::LLFloaterAvatar(const LLSD& key)  LLFloaterAvatar::~LLFloaterAvatar()  { -	LLMediaCtrl* avatar_picker = findChild<LLMediaCtrl>("avatar_picker_contents"); -	if (avatar_picker) +	if (mAvatarPicker)  	{ -		avatar_picker->navigateStop(); -		avatar_picker->clearCache();          //images are reloading each time already -		avatar_picker->unloadMediaSource(); +		mAvatarPicker->navigateStop(); +        mAvatarPicker->clearCache();          //images are reloading each time already +        mAvatarPicker->unloadMediaSource();  	}  }  BOOL LLFloaterAvatar::postBuild()  { +    mAvatarPicker = findChild<LLMediaCtrl>("avatar_picker_contents"); +    if (mAvatarPicker) +    { +        mAvatarPicker->clearCache(); +    }  	enableResizeCtrls(true, true, false);  	return TRUE;  } diff --git a/indra/newview/llfloateravatar.h b/indra/newview/llfloateravatar.h index cadc5e4028..76e9372709 100644 --- a/indra/newview/llfloateravatar.h +++ b/indra/newview/llfloateravatar.h @@ -29,6 +29,7 @@  #define LL_FLOATER_AVATAR_H  #include "llfloater.h" +class LLMediaCtrl;  class LLFloaterAvatar:  	public LLFloater @@ -38,6 +39,8 @@ private:  	LLFloaterAvatar(const LLSD& key);  	/*virtual*/	~LLFloaterAvatar();  	/*virtual*/	BOOL postBuild(); + +    LLMediaCtrl* mAvatarPicker;  };  #endif diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index 0186c4aebe..2422596f60 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -428,13 +428,18 @@ void LLFloaterAvatarPicker::findCoro(std::string url, LLUUID queryID, std::strin      if (status || (status == LLCore::HttpStatus(HTTP_BAD_REQUEST)))      { -        LLFloaterAvatarPicker* floater = -            LLFloaterReg::findTypedInstance<LLFloaterAvatarPicker>("avatar_picker", name); -        if (floater) -        { -            result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); -            floater->processResponse(queryID, result); -        } +        result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); +    } +    else +    { +        result["failure_reason"] = status.toString(); +    } + +    LLFloaterAvatarPicker* floater = +        LLFloaterReg::findTypedInstance<LLFloaterAvatarPicker>("avatar_picker", name); +    if (floater) +    { +        floater->processResponse(queryID, result);      }  } @@ -672,59 +677,67 @@ void LLFloaterAvatarPicker::processResponse(const LLUUID& query_id, const LLSD&  	{  		LLScrollListCtrl* search_results = getChild<LLScrollListCtrl>("SearchResults"); -		LLSD agents = content["agents"]; - -		// clear "Searching" label on first results -		search_results->deleteAllItems(); - -		LLSD item; -		LLSD::array_const_iterator it = agents.beginArray(); -		for ( ; it != agents.endArray(); ++it) -		{ -			const LLSD& row = *it; -			if (row["id"].asUUID() != gAgent.getID() || !mExcludeAgentFromSearchResults) -			{ -				item["id"] = row["id"]; -				LLSD& columns = item["columns"]; -				columns[0]["column"] = "name"; -				columns[0]["value"] = row["display_name"]; -				columns[1]["column"] = "username"; -				columns[1]["value"] = row["username"]; -				search_results->addElement(item); - -				// add the avatar name to our list -				LLAvatarName avatar_name; -				avatar_name.fromLLSD(row); -				sAvatarNameMap[row["id"].asUUID()] = avatar_name; -			} -		} +        // clear "Searching" label on first results +        search_results->deleteAllItems(); -		if (search_results->isEmpty()) -		{ -			std::string name = "'" + getChild<LLUICtrl>("Edit")->getValue().asString() + "'"; -			LLSD item; -			item["id"] = LLUUID::null; -			item["columns"][0]["column"] = "name"; -			item["columns"][0]["value"] = name; -			item["columns"][1]["column"] = "username"; -			item["columns"][1]["value"] = getString("not_found_text"); -			search_results->addElement(item); -			search_results->setEnabled(false); -			getChildView("ok_btn")->setEnabled(false); -		} -		else -		{ -			getChildView("ok_btn")->setEnabled(true); -			search_results->setEnabled(true); -			search_results->sortByColumnIndex(1, TRUE); -			std::string text = getChild<LLUICtrl>("Edit")->getValue().asString(); -			if (!search_results->selectItemByLabel(text, TRUE, 1)) -			{ -				search_results->selectFirstItem(); -			}			 -			onList(); -			search_results->setFocus(TRUE); -		} +        if (content.has("failure_reason")) +        { +            getChild<LLScrollListCtrl>("SearchResults")->setCommentText(content["failure_reason"].asString()); +            getChildView("ok_btn")->setEnabled(false); +        } +        else +        { +            LLSD agents = content["agents"]; + +            LLSD item; +            LLSD::array_const_iterator it = agents.beginArray(); +            for (; it != agents.endArray(); ++it) +            { +                const LLSD& row = *it; +                if (row["id"].asUUID() != gAgent.getID() || !mExcludeAgentFromSearchResults) +                { +                    item["id"] = row["id"]; +                    LLSD& columns = item["columns"]; +                    columns[0]["column"] = "name"; +                    columns[0]["value"] = row["display_name"]; +                    columns[1]["column"] = "username"; +                    columns[1]["value"] = row["username"]; +                    search_results->addElement(item); + +                    // add the avatar name to our list +                    LLAvatarName avatar_name; +                    avatar_name.fromLLSD(row); +                    sAvatarNameMap[row["id"].asUUID()] = avatar_name; +                } +            } + +            if (search_results->isEmpty()) +            { +                std::string name = "'" + getChild<LLUICtrl>("Edit")->getValue().asString() + "'"; +                LLSD item; +                item["id"] = LLUUID::null; +                item["columns"][0]["column"] = "name"; +                item["columns"][0]["value"] = name; +                item["columns"][1]["column"] = "username"; +                item["columns"][1]["value"] = getString("not_found_text"); +                search_results->addElement(item); +                search_results->setEnabled(false); +                getChildView("ok_btn")->setEnabled(false); +            } +            else +            { +                getChildView("ok_btn")->setEnabled(true); +                search_results->setEnabled(true); +                search_results->sortByColumnIndex(1, TRUE); +                std::string text = getChild<LLUICtrl>("Edit")->getValue().asString(); +                if (!search_results->selectItemByLabel(text, TRUE, 1)) +                { +                    search_results->selectFirstItem(); +                } +                onList(); +                search_results->setFocus(TRUE); +            } +        }  	}  } diff --git a/indra/newview/llfloateravatarrendersettings.cpp b/indra/newview/llfloateravatarrendersettings.cpp index b8f854feb3..8b28f6941e 100644 --- a/indra/newview/llfloateravatarrendersettings.cpp +++ b/indra/newview/llfloateravatarrendersettings.cpp @@ -89,6 +89,7 @@ BOOL LLFloaterAvatarRenderSettings::postBuild()      LLFloater::postBuild();      mAvatarSettingsList = getChild<LLNameListCtrl>("render_settings_list");      mAvatarSettingsList->setRightMouseDownCallback(boost::bind(&LLFloaterAvatarRenderSettings::onAvatarListRightClick, this, _1, _2, _3)); +    mAvatarSettingsList->setAlternateSort();      getChild<LLFilterEditor>("people_filter_input")->setCommitCallback(boost::bind(&LLFloaterAvatarRenderSettings::onFilterEdit, this, _2));  	return TRUE; @@ -138,8 +139,8 @@ void LLFloaterAvatarRenderSettings::updateList()              item_params.columns.add().value(av_name.getCompleteName()).column("name");              std::string setting = getString(iter->second == 1 ? "av_never_render" : "av_always_render");              item_params.columns.add().value(setting).column("setting"); -            std::string timestamp = createTimestamp(LLRenderMuteList::getInstance()->getVisualMuteDate(iter->first)); -            item_params.columns.add().value(timestamp).column("timestamp"); +            S32 mute_date = LLRenderMuteList::getInstance()->getVisualMuteDate(iter->first); +            item_params.columns.add().value(createTimestamp(mute_date)).column("timestamp").alt_value(std::to_string(mute_date));              mAvatarSettingsList->addNameItemRow(item_params);          }      } diff --git a/indra/newview/llfloaterbump.cpp b/indra/newview/llfloaterbump.cpp index 33e4c7cd5f..307ab8c4d1 100644 --- a/indra/newview/llfloaterbump.cpp +++ b/indra/newview/llfloaterbump.cpp @@ -69,6 +69,12 @@ LLFloaterBump::LLFloaterBump(const LLSD& key)  // Destroys the object  LLFloaterBump::~LLFloaterBump()  { +	auto menu = mPopupMenuHandle.get(); +	if (menu) +	{ +		menu->die(); +		mPopupMenuHandle.markDead(); +	}  }  BOOL LLFloaterBump::postBuild() @@ -77,11 +83,15 @@ BOOL LLFloaterBump::postBuild()  	mList->setAllowMultipleSelection(false);  	mList->setRightMouseDownCallback(boost::bind(&LLFloaterBump::onScrollListRightClicked, this, _1, _2, _3)); -	mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>("menu_avatar_other.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); -	mPopupMenu->setItemVisible(std::string("Normal"), false); -	mPopupMenu->setItemVisible(std::string("Always use impostor"), false); -	mPopupMenu->setItemVisible(std::string("Never use impostor"), false); -	mPopupMenu->setItemVisible(std::string("Impostor seperator"), false); +	LLContextMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>("menu_avatar_other.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); +	if (menu) +	{ +		mPopupMenuHandle = menu->getHandle(); +		menu->setItemVisible(std::string("Normal"), false); +		menu->setItemVisible(std::string("Always use impostor"), false); +		menu->setItemVisible(std::string("Never use impostor"), false); +		menu->setItemVisible(std::string("Impostor seperator"), false); +	}  	return TRUE;  } @@ -176,18 +186,19 @@ void LLFloaterBump::onScrollListRightClicked(LLUICtrl* ctrl, S32 x, S32 y)  	if (!gMeanCollisionList.empty())  	{  		LLScrollListItem* item = mList->hitItem(x, y); -		if (item && mPopupMenu) +		auto menu = mPopupMenuHandle.get(); +		if (item && menu)  		{  			mItemUUID = item->getUUID(); -			mPopupMenu->buildDrawLabels(); -			mPopupMenu->updateParent(LLMenuGL::sMenuContainer); +			menu->buildDrawLabels(); +			menu->updateParent(LLMenuGL::sMenuContainer);  			std::string mute_msg = (LLMuteList::getInstance()->isMuted(mItemUUID, mNames[mItemUUID])) ? "UnmuteAvatar" : "MuteAvatar"; -			mPopupMenu->getChild<LLUICtrl>("Avatar Mute")->setValue(LLTrans::getString(mute_msg)); -			mPopupMenu->setItemEnabled(std::string("Zoom In"), bool(gObjectList.findObject(mItemUUID))); +			menu->getChild<LLUICtrl>("Avatar Mute")->setValue(LLTrans::getString(mute_msg)); +			menu->setItemEnabled(std::string("Zoom In"), bool(gObjectList.findObject(mItemUUID))); -			((LLContextMenu*)mPopupMenu)->show(x, y); -			LLMenuGL::showPopup(ctrl, mPopupMenu, x, y); +			menu->show(x, y); +			LLMenuGL::showPopup(ctrl, menu, x, y);  		}  	}  } diff --git a/indra/newview/llfloaterbump.h b/indra/newview/llfloaterbump.h index ce52c75255..d2f9fabdd3 100644 --- a/indra/newview/llfloaterbump.h +++ b/indra/newview/llfloaterbump.h @@ -68,7 +68,7 @@ private:  	virtual ~LLFloaterBump();  	LLScrollListCtrl* mList; -	LLMenuGL* mPopupMenu; +	LLHandle<LLContextMenu> mPopupMenuHandle;  	LLUUID mItemUUID;  	typedef std::map<LLUUID, std::string> uuid_map_t; diff --git a/indra/newview/llfloatercreatelandmark.cpp b/indra/newview/llfloatercreatelandmark.cpp index 7def855d83..b82d8a29ba 100644 --- a/indra/newview/llfloatercreatelandmark.cpp +++ b/indra/newview/llfloatercreatelandmark.cpp @@ -316,7 +316,6 @@ void LLFloaterCreateLandmark::onSaveClicked()  	LLStringUtil::trim(current_title_value);  	LLStringUtil::trim(current_notes_value); -	LLUUID item_id = mItem->getUUID();  	LLUUID folder_id = mFolderCombo->getValue().asUUID();  	bool change_parent = folder_id != mItem->getParentUUID(); diff --git a/indra/newview/llfloaterdisplayname.cpp b/indra/newview/llfloaterdisplayname.cpp index 3b0c67415a..19bc865d8b 100644 --- a/indra/newview/llfloaterdisplayname.cpp +++ b/indra/newview/llfloaterdisplayname.cpp @@ -47,6 +47,7 @@ public:  	virtual ~LLFloaterDisplayName() { }  	/*virtual*/	BOOL	postBuild();  	void onSave(); +	void onReset();  	void onCancel();  	/*virtual*/ void onOpen(const LLSD& key); @@ -101,6 +102,7 @@ void LLFloaterDisplayName::onOpen(const LLSD& key)  BOOL LLFloaterDisplayName::postBuild()  { +	getChild<LLUICtrl>("reset_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onReset, this));	  	getChild<LLUICtrl>("cancel_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onCancel, this));	  	getChild<LLUICtrl>("save_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onSave, this));	 @@ -156,6 +158,20 @@ void LLFloaterDisplayName::onCancel()  	setVisible(false);  } +void LLFloaterDisplayName::onReset() +{ +    LLAvatarName av_name; +    if (!LLAvatarNameCache::get(gAgent.getID(), &av_name)) +    { +        return; +    } +    getChild<LLUICtrl>("display_name_editor")->setValue(av_name.getCompleteName()); + +    getChild<LLUICtrl>("display_name_confirm")->clear(); +    getChild<LLUICtrl>("display_name_confirm")->setFocus(TRUE); +} + +  void LLFloaterDisplayName::onSave()  {  	std::string display_name_utf8 = getChild<LLUICtrl>("display_name_editor")->getValue().asString(); diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index 703b5d0011..2720b7fcf7 100644 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -211,6 +211,7 @@ BOOL LLFloaterIMContainer::postBuild()      p.options_menu = "menu_conversation.xml";  	mConversationsRoot = LLUICtrlFactory::create<LLFolderView>(p);      mConversationsRoot->setCallbackRegistrar(&mCommitCallbackRegistrar); +	mConversationsRoot->setEnableRegistrar(&mEnableCallbackRegistrar);  	// Add listener to conversation model events  	mConversationsEventStream.listen("ConversationsRefresh", boost::bind(&LLFloaterIMContainer::onConversationModelEvent, this, _1)); diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index 204cd03b09..78271369d2 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -316,6 +316,7 @@ BOOL LLFloaterIMSessionTab::postBuild()      p.name = "root";  	mConversationsRoot = LLUICtrlFactory::create<LLFolderView>(p);      mConversationsRoot->setCallbackRegistrar(&mCommitCallbackRegistrar); +	mConversationsRoot->setEnableRegistrar(&mEnableCallbackRegistrar);  	// Attach that root to the scroller  	mScroller->addChild(mConversationsRoot);  	mConversationsRoot->setScrollContainer(mScroller); diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 66a245b779..6f8f73bca0 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1740,7 +1740,7 @@ void LLFloaterModelPreview::toggleCalculateButton(bool visible)  		childSetTextArg("download_weight", "[ST]", tbd);  		childSetTextArg("server_weight", "[SIM]", tbd);  		childSetTextArg("physics_weight", "[PH]", tbd); -		if (!mModelPhysicsFee.isMap() || mModelPhysicsFee.emptyMap()) +		if (!mModelPhysicsFee.isMap() || (mModelPhysicsFee.size() == 0))  		{  			childSetTextArg("upload_fee", "[FEE]", tbd);  		} diff --git a/indra/newview/llfloateropenobject.cpp b/indra/newview/llfloateropenobject.cpp index 2a1749bd42..a682064dad 100644 --- a/indra/newview/llfloateropenobject.cpp +++ b/indra/newview/llfloateropenobject.cpp @@ -56,8 +56,6 @@ LLFloaterOpenObject::LLFloaterOpenObject(const LLSD& key)  	mDirty(TRUE)  {  	mCommitCallbackRegistrar.add("OpenObject.MoveToInventory",	boost::bind(&LLFloaterOpenObject::onClickMoveToInventory, this)); -	mCommitCallbackRegistrar.add("OpenObject.MoveAndWear",		boost::bind(&LLFloaterOpenObject::onClickMoveAndWear, this)); -	mCommitCallbackRegistrar.add("OpenObject.ReplaceOutfit",	boost::bind(&LLFloaterOpenObject::onClickReplace, this));  	mCommitCallbackRegistrar.add("OpenObject.Cancel",			boost::bind(&LLFloaterOpenObject::onClickCancel, this));  } @@ -243,18 +241,6 @@ void LLFloaterOpenObject::onClickMoveToInventory()  	closeFloater();  } -void LLFloaterOpenObject::onClickMoveAndWear() -{ -	moveToInventory(true, false); -	closeFloater(); -} - -void LLFloaterOpenObject::onClickReplace() -{ -	moveToInventory(true, true); -	closeFloater(); -} -  void LLFloaterOpenObject::onClickCancel()  {  	closeFloater(); diff --git a/indra/newview/llfloateropenobject.h b/indra/newview/llfloateropenobject.h index 2e761f99bf..745753316b 100644 --- a/indra/newview/llfloateropenobject.h +++ b/indra/newview/llfloateropenobject.h @@ -63,8 +63,6 @@ protected:  	void moveToInventory(bool wear, bool replace = false);  	void onClickMoveToInventory(); -	void onClickMoveAndWear(); -	void onClickReplace();  	void onClickCancel();  	static void callbackCreateInventoryCategory(const LLUUID& category_id, LLUUID object_id, bool wear, bool replace = false);  	static void callbackMoveInventory(S32 result, void* data); diff --git a/indra/newview/llfloateroutfitphotopreview.cpp b/indra/newview/llfloateroutfitphotopreview.cpp index 6c39db730c..ade258aef7 100644 --- a/indra/newview/llfloateroutfitphotopreview.cpp +++ b/indra/newview/llfloateroutfitphotopreview.cpp @@ -234,7 +234,6 @@ void LLFloaterOutfitPhotoPreview::updateImageID()  	if(item)  	{  		mImageID = item->getAssetUUID(); -		LLPermissions perm(item->getPermissions());  	}  	else  	{ diff --git a/indra/newview/llfloaterpathfindinglinksets.cpp b/indra/newview/llfloaterpathfindinglinksets.cpp index 1e46d7a402..03aede94c6 100644 --- a/indra/newview/llfloaterpathfindinglinksets.cpp +++ b/indra/newview/llfloaterpathfindinglinksets.cpp @@ -44,6 +44,7 @@  #include "llpathfindinglinkset.h"  #include "llpathfindinglinksetlist.h"  #include "llpathfindingmanager.h" +#include "llsearcheditor.h"  #include "llscrolllistitem.h"  #include "llsd.h"  #include "lltextbase.h" @@ -114,17 +115,13 @@ BOOL LLFloaterPathfindingLinksets::postBuild()  {  	mBeaconColor = LLUIColorTable::getInstance()->getColor("PathfindingLinksetBeaconColor"); -	mFilterByName = findChild<LLLineEditor>("filter_by_name"); -	llassert(mFilterByName != NULL); -	mFilterByName->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onApplyAllFilters, this)); -	mFilterByName->setSelectAllonFocusReceived(true); -	mFilterByName->setCommitOnFocusLost(true); - -	mFilterByDescription = findChild<LLLineEditor>("filter_by_description"); -	llassert(mFilterByDescription != NULL); -	mFilterByDescription->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onApplyAllFilters, this)); -	mFilterByDescription->setSelectAllonFocusReceived(true); -	mFilterByDescription->setCommitOnFocusLost(true); +    mFilterByName = getChild<LLSearchEditor>("filter_by_name"); +    mFilterByName->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onApplyAllFilters, this)); +    mFilterByName->setCommitOnFocusLost(true); + +    mFilterByDescription = getChild<LLSearchEditor>("filter_by_description"); +    mFilterByDescription->setCommitCallback(boost::bind(&LLFloaterPathfindingLinksets::onApplyAllFilters, this)); +    mFilterByDescription->setCommitOnFocusLost(true);  	mFilterByLinksetUse = findChild<LLComboBox>("filter_by_linkset_use");  	llassert(mFilterByLinksetUse != NULL); diff --git a/indra/newview/llfloaterpathfindinglinksets.h b/indra/newview/llfloaterpathfindinglinksets.h index 7149da9215..a954d8a8ec 100644 --- a/indra/newview/llfloaterpathfindinglinksets.h +++ b/indra/newview/llfloaterpathfindinglinksets.h @@ -42,6 +42,7 @@ class LLSD;  class LLTextBase;  class LLUICtrl;  class LLVector3; +class LLSearchEditor;  class LLFloaterPathfindingLinksets : public LLFloaterPathfindingObjects  { @@ -105,8 +106,8 @@ private:  	LLPathfindingLinkset::ELinksetUse convertToLinksetUse(LLSD pXuiValue) const;  	LLSD                              convertToXuiValue(LLPathfindingLinkset::ELinksetUse pLinksetUse) const; -	LLLineEditor     *mFilterByName; -	LLLineEditor     *mFilterByDescription; +    LLSearchEditor   *mFilterByName; +    LLSearchEditor   *mFilterByDescription;  	LLComboBox       *mFilterByLinksetUse;  	LLComboBox       *mEditLinksetUse;  	LLScrollListItem *mEditLinksetUseUnset; diff --git a/indra/newview/llfloaterscriptlimits.cpp b/indra/newview/llfloaterscriptlimits.cpp index 3746b9b6c2..40fe11b309 100644 --- a/indra/newview/llfloaterscriptlimits.cpp +++ b/indra/newview/llfloaterscriptlimits.cpp @@ -421,7 +421,6 @@ void LLPanelScriptLimitsRegionMemory::setRegionDetails(LLSD content)  	for(S32 i = 0; i < number_parcels; i++)  	{  		std::string parcel_name = content["parcels"][i]["name"].asString(); -		LLUUID parcel_id = content["parcels"][i]["id"].asUUID();  		S32 number_objects = content["parcels"][i]["objects"].size();  		S32 local_id = 0; diff --git a/indra/newview/llfloatersearch.cpp b/indra/newview/llfloatersearch.cpp index bb3ed77772..7e6af45515 100644 --- a/indra/newview/llfloatersearch.cpp +++ b/indra/newview/llfloatersearch.cpp @@ -45,7 +45,7 @@ class LLSearchHandler : public LLCommandHandler  {  public:  	// requires trusted browser to trigger -	LLSearchHandler() : LLCommandHandler("search", UNTRUSTED_THROTTLE) { } +	LLSearchHandler() : LLCommandHandler("search", UNTRUSTED_CLICK_ONLY) { }  	bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web)  	{  		if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableSearch")) diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp index 186994c857..3c7f341613 100644 --- a/indra/newview/llfloatersettingsdebug.cpp +++ b/indra/newview/llfloatersettingsdebug.cpp @@ -2,9 +2,9 @@   * @file llfloatersettingsdebug.cpp   * @brief floater for debugging internal viewer settings   * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * $LicenseInfo:firstyear=2022&license=viewerlgpl$   * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2022, Linden Research, Inc.   *    * This library is free software; you can redistribute it and/or   * modify it under the terms of the GNU Lesser General Public @@ -27,8 +27,8 @@  #include "llviewerprecompiledheaders.h"  #include "llfloatersettingsdebug.h"  #include "llfloater.h" +#include "llfiltereditor.h"  #include "lluictrlfactory.h" -//#include "llfirstuse.h"  #include "llcombobox.h"  #include "llspinctrl.h"  #include "llcolorswatch.h" @@ -37,12 +37,11 @@  LLFloaterSettingsDebug::LLFloaterSettingsDebug(const LLSD& key)  -:	LLFloater(key) +:   LLFloater(key), +    mSettingList(NULL)  { -	mCommitCallbackRegistrar.add("SettingSelect",	boost::bind(&LLFloaterSettingsDebug::onSettingSelect, this,_1));  	mCommitCallbackRegistrar.add("CommitSettings",	boost::bind(&LLFloaterSettingsDebug::onCommitSettings, this));  	mCommitCallbackRegistrar.add("ClickDefault",	boost::bind(&LLFloaterSettingsDebug::onClickDefault, this)); -  }  LLFloaterSettingsDebug::~LLFloaterSettingsDebug() @@ -50,59 +49,43 @@ LLFloaterSettingsDebug::~LLFloaterSettingsDebug()  BOOL LLFloaterSettingsDebug::postBuild()  { -	LLComboBox* settings_combo = getChild<LLComboBox>("settings_combo"); +    enableResizeCtrls(true, false, true); -	struct f : public LLControlGroup::ApplyFunctor -	{ -		LLComboBox* combo; -		f(LLComboBox* c) : combo(c) {} -		virtual void apply(const std::string& name, LLControlVariable* control) -		{ -			if (!control->isHiddenFromSettingsEditor()) -			{ -				combo->add(name, (void*)control); -			} -		} -	} func(settings_combo); +    mComment = getChild<LLTextEditor>("comment_text"); -	std::string key = getKey().asString(); -	if (key == "all" || key == "base") -	{ -		gSavedSettings.applyToAll(&func); -	} -	if (key == "all" || key == "account") -	{ -		gSavedPerAccountSettings.applyToAll(&func); -	} +    getChild<LLFilterEditor>("filter_input")->setCommitCallback(boost::bind(&LLFloaterSettingsDebug::setSearchFilter, this, _2)); + +    mSettingList = getChild<LLScrollListCtrl>("setting_list"); +    mSettingList->setCommitOnSelectionChange(TRUE); +    mSettingList->setCommitCallback(boost::bind(&LLFloaterSettingsDebug::onSettingSelect, this)); + +    updateList(); + +    gSavedSettings.getControl("DebugSettingsHideDefault")->getCommitSignal()->connect(boost::bind(&LLFloaterSettingsDebug::updateList, this, false)); -	settings_combo->sortByName(); -	settings_combo->updateSelection(); -	mComment = getChild<LLTextEditor>("comment_text");  	return TRUE;  }  void LLFloaterSettingsDebug::draw()  { -	LLComboBox* settings_combo = getChild<LLComboBox>("settings_combo"); -	LLControlVariable* controlp = (LLControlVariable*)settings_combo->getCurrentUserdata(); -	updateControl(controlp); +    LLScrollListItem* first_selected = mSettingList->getFirstSelected(); +    if (first_selected) +    { +        LLControlVariable* controlp = (LLControlVariable*)first_selected->getUserdata(); +        updateControl(controlp); +    }  	LLFloater::draw();  } -//static  -void LLFloaterSettingsDebug::onSettingSelect(LLUICtrl* ctrl) -{ -	LLComboBox* combo_box = (LLComboBox*)ctrl; -	LLControlVariable* controlp = (LLControlVariable*)combo_box->getCurrentUserdata(); - -	updateControl(controlp); -} -  void LLFloaterSettingsDebug::onCommitSettings()  { -	LLComboBox* settings_combo = getChild<LLComboBox>("settings_combo"); -	LLControlVariable* controlp = (LLControlVariable*)settings_combo->getCurrentUserdata(); +    LLScrollListItem* first_selected = mSettingList->getFirstSelected(); +    if (!first_selected) +    { +        return; +    } +    LLControlVariable* controlp = (LLControlVariable*)first_selected->getUserdata();  	if (!controlp)  	{ @@ -176,19 +159,23 @@ void LLFloaterSettingsDebug::onCommitSettings()  	  default:  		break;  	} +    updateDefaultColumn(controlp);  }  // static  void LLFloaterSettingsDebug::onClickDefault()  { -	LLComboBox* settings_combo = getChild<LLComboBox>("settings_combo"); -	LLControlVariable* controlp = (LLControlVariable*)settings_combo->getCurrentUserdata(); - -	if (controlp) -	{ -		controlp->resetToDefault(true); -		updateControl(controlp); -	} +    LLScrollListItem* first_selected = mSettingList->getFirstSelected(); +    if (first_selected) +    { +        LLControlVariable* controlp = (LLControlVariable*)first_selected->getUserdata(); +        if (controlp) +        { +            controlp->resetToDefault(true); +            updateDefaultColumn(controlp); +            updateControl(controlp); +        } +    }  }  // we've switched controls, or doing per-frame update, so update spinners, etc. @@ -207,23 +194,30 @@ void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp)  		return;  	} -	spinner1->setVisible(FALSE); -	spinner2->setVisible(FALSE); -	spinner3->setVisible(FALSE); -	spinner4->setVisible(FALSE); -	color_swatch->setVisible(FALSE); -	getChildView("val_text")->setVisible( FALSE); -	mComment->setText(LLStringUtil::null); +    hideUIControls(); -	if (controlp) +	if (controlp && !isSettingHidden(controlp))  	{  		eControlType type = controlp->type();  		//hide combo box only for non booleans, otherwise this will result in the combo box closing every frame  		getChildView("boolean_combo")->setVisible( type == TYPE_BOOLEAN); -		 +        getChildView("default_btn")->setVisible(true); +        getChildView("setting_name_txt")->setVisible(true); +        getChild<LLTextBox>("setting_name_txt")->setText(controlp->getName()); +        getChild<LLTextBox>("setting_name_txt")->setToolTip(controlp->getName()); +        mComment->setVisible(true); + +        std::string old_text = mComment->getText(); +        std::string new_text = controlp->getComment(); +        // Don't setText if not nessesary, it will reset scroll +        // This is a debug UI that reads from xml, there might +        // be use cases where comment changes, but not the name +        if (old_text != new_text) +        { +            mComment->setText(controlp->getComment()); +        } -		mComment->setText(controlp->getComment());  		spinner1->setMaxValue(F32_MAX);  		spinner2->setMaxValue(F32_MAX);  		spinner3->setMaxValue(F32_MAX); @@ -479,3 +473,166 @@ void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp)  	}  } + +void LLFloaterSettingsDebug::updateList(bool skip_selection) +{ +    std::string last_selected; +    LLScrollListItem* item = mSettingList->getFirstSelected(); +    if (item) +    { +        LLScrollListCell* cell = item->getColumn(1); +        if (cell) +        { +            last_selected = cell->getValue().asString(); +         } +    } + +    mSettingList->deleteAllItems(); +    struct f : public LLControlGroup::ApplyFunctor +    { +        LLScrollListCtrl* setting_list; +        LLFloaterSettingsDebug* floater; +        std::string selected_setting; +        bool skip_selection; +        f(LLScrollListCtrl* list, LLFloaterSettingsDebug* floater, std::string setting, bool skip_selection)  +            : setting_list(list), floater(floater), selected_setting(setting), skip_selection(skip_selection) {} +        virtual void apply(const std::string& name, LLControlVariable* control) +        { +            if (!control->isHiddenFromSettingsEditor() && floater->matchesSearchFilter(name) && !floater->isSettingHidden(control)) +            { +                LLSD row; + +                row["columns"][0]["column"] = "changed_setting"; +                row["columns"][0]["value"] = control->isDefault() ? "" : "*"; + +                row["columns"][1]["column"] = "setting"; +                row["columns"][1]["value"] = name; + +                LLScrollListItem* item = setting_list->addElement(row, ADD_BOTTOM, (void*)control); +                if (!floater->mSearchFilter.empty() && (selected_setting == name) && !skip_selection) +                { +                    std::string lower_name(name); +                    LLStringUtil::toLower(lower_name); +                    if (LLStringUtil::startsWith(lower_name, floater->mSearchFilter)) +                    { +                        item->setSelected(true); +                    } +                } +            } +        } +    } func(mSettingList, this, last_selected, skip_selection); + +    std::string key = getKey().asString(); +    if (key == "all" || key == "base") +    { +        gSavedSettings.applyToAll(&func); +    } +    if (key == "all" || key == "account") +    { +        gSavedPerAccountSettings.applyToAll(&func); +    } + + +    if (!mSettingList->isEmpty()) +    { +        if (mSettingList->hasSelectedItem()) +        { +            mSettingList->scrollToShowSelected(); +        } +        else if (!mSettingList->hasSelectedItem() && !mSearchFilter.empty() && !skip_selection) +        { +            if (!mSettingList->selectItemByPrefix(mSearchFilter, false, 1)) +            { +                mSettingList->selectFirstItem(); +            } +            mSettingList->scrollToShowSelected(); +        } +    } +    else +    { +        LLSD row; + +        row["columns"][0]["column"] = "changed_setting"; +        row["columns"][0]["value"] = ""; +        row["columns"][1]["column"] = "setting"; +        row["columns"][1]["value"] = "No matching settings."; + +        mSettingList->addElement(row); +        hideUIControls(); +    } +} + +void LLFloaterSettingsDebug::onSettingSelect() +{ +    LLScrollListItem* first_selected = mSettingList->getFirstSelected(); +    if (first_selected) +    { +        LLControlVariable* controlp = (LLControlVariable*)first_selected->getUserdata(); +        if (controlp) +        { +            updateControl(controlp); +        } +    } +} + +void LLFloaterSettingsDebug::setSearchFilter(const std::string& filter) +{ +    if(mSearchFilter == filter) +        return; +    mSearchFilter = filter; +    LLStringUtil::toLower(mSearchFilter); +    updateList(); +} + +bool LLFloaterSettingsDebug::matchesSearchFilter(std::string setting_name) +{ +    // If the search filter is empty, everything passes. +    if (mSearchFilter.empty()) return true; + +    LLStringUtil::toLower(setting_name); +    std::string::size_type match_name = setting_name.find(mSearchFilter); + +    return (std::string::npos != match_name); +} + +bool LLFloaterSettingsDebug::isSettingHidden(LLControlVariable* control) +{ +    static LLCachedControl<bool> hide_default(gSavedSettings, "DebugSettingsHideDefault", false); +    return hide_default && control->isDefault(); +} + +void LLFloaterSettingsDebug::updateDefaultColumn(LLControlVariable* control) +{ +    if (isSettingHidden(control)) +    { +        hideUIControls(); +        updateList(true); +        return; +    } + +    LLScrollListItem* item = mSettingList->getFirstSelected(); +    if (item) +    { +        LLScrollListCell* cell = item->getColumn(0); +        if (cell) +        { +            std::string is_default = control->isDefault() ? "" : "*"; +            cell->setValue(is_default); +        } +    } +} + +void LLFloaterSettingsDebug::hideUIControls() +{ +    getChildView("val_spinner_1")->setVisible(false); +    getChildView("val_spinner_2")->setVisible(false); +    getChildView("val_spinner_3")->setVisible(false); +    getChildView("val_spinner_4")->setVisible(false); +    getChildView("val_color_swatch")->setVisible(false); +    getChildView("val_text")->setVisible(false); +    getChildView("default_btn")->setVisible(false); +    getChildView("boolean_combo")->setVisible(false); +    getChildView("setting_name_txt")->setVisible(false); +    mComment->setVisible(false); +} + diff --git a/indra/newview/llfloatersettingsdebug.h b/indra/newview/llfloatersettingsdebug.h index f07e0557e3..888eaadcbd 100644 --- a/indra/newview/llfloatersettingsdebug.h +++ b/indra/newview/llfloatersettingsdebug.h @@ -2,9 +2,9 @@   * @file llfloatersettingsdebug.h   * @brief floater for debugging internal viewer settings   * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * $LicenseInfo:firstyear=2022&license=viewerlgpl$   * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2022, Linden Research, Inc.   *    * This library is free software; you can redistribute it and/or   * modify it under the terms of the GNU Lesser General Public @@ -30,6 +30,8 @@  #include "llcontrol.h"  #include "llfloater.h" +class LLScrollListCtrl; +  class LLFloaterSettingsDebug   :	public LLFloater  { @@ -42,18 +44,31 @@ public:  	void updateControl(LLControlVariable* control); -	void onSettingSelect(LLUICtrl* ctrl);  	void onCommitSettings();  	void onClickDefault(); +    bool matchesSearchFilter(std::string setting_name); +    bool isSettingHidden(LLControlVariable* control); +  private:  	// key - selects which settings to show, one of:  	// "all", "base", "account", "skin"  	LLFloaterSettingsDebug(const LLSD& key);  	virtual ~LLFloaterSettingsDebug(); + +    void updateList(bool skip_selection = false); +    void onSettingSelect(); +    void setSearchFilter(const std::string& filter); + +    void updateDefaultColumn(LLControlVariable* control); +    void hideUIControls(); + +    LLScrollListCtrl* mSettingList;  protected:  	class LLTextEditor* mComment; + +    std::string mSearchFilter;  };  #endif //LLFLOATERDEBUGSETTINGS_H diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index 01bfae8934..704abd269f 100755 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -122,7 +122,7 @@ class LLWorldMapHandler : public LLCommandHandler  {  public:  	// requires trusted browser to trigger -	LLWorldMapHandler() : LLCommandHandler("worldmap", UNTRUSTED_THROTTLE ) { } +	LLWorldMapHandler() : LLCommandHandler("worldmap", UNTRUSTED_CLICK_ONLY ) { }  	bool handle(const LLSD& params, const LLSD& query_map,  				LLMediaCtrl* web) @@ -159,7 +159,7 @@ class LLMapTrackAvatarHandler : public LLCommandHandler  {  public:  	// requires trusted browser to trigger -	LLMapTrackAvatarHandler() : LLCommandHandler("maptrackavatar", UNTRUSTED_THROTTLE)  +	LLMapTrackAvatarHandler() : LLCommandHandler("maptrackavatar", UNTRUSTED_CLICK_ONLY)   	{   	} diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp index dbeb157323..be52e280e1 100644 --- a/indra/newview/llgroupactions.cpp +++ b/indra/newview/llgroupactions.cpp @@ -52,7 +52,32 @@ class LLGroupHandler : public LLCommandHandler  {  public:  	// requires trusted browser to trigger -	LLGroupHandler() : LLCommandHandler("group", UNTRUSTED_THROTTLE) { } +	LLGroupHandler() : LLCommandHandler("group", UNTRUSTED_CLICK_ONLY) { } + +    virtual bool canHandleUntrusted( +        const LLSD& params, +        const LLSD& query_map, +        LLMediaCtrl* web, +        const std::string& nav_type) +    { +        if (params.size() < 1) +        { +            return true; // don't block, will fail later +        } + +        if (nav_type == NAV_TYPE_CLICKED) +        { +            return true; +        } + +        const std::string verb = params[0].asString(); +        if (verb == "create") +        { +            return false; +        } +        return true; +    } +  	bool handle(const LLSD& tokens, const LLSD& query_map,  				LLMediaCtrl* web)  	{ diff --git a/indra/newview/llhudnametag.cpp b/indra/newview/llhudnametag.cpp index 952fbf8e4b..ab6a64157c 100644 --- a/indra/newview/llhudnametag.cpp +++ b/indra/newview/llhudnametag.cpp @@ -56,7 +56,6 @@ const F32 HORIZONTAL_PADDING = 16.f;  const F32 VERTICAL_PADDING = 12.f;  const F32 LINE_PADDING = 3.f;			// aka "leading"  const F32 BUFFER_SIZE = 2.f; -const F32 HUD_TEXT_MAX_WIDTH = 190.f;  const S32 NUM_OVERLAP_ITERATIONS = 10;  const F32 POSITION_DAMPING_TC = 0.2f;  const F32 MAX_STABLE_CAMERA_VELOCITY = 0.1f; @@ -67,6 +66,8 @@ const F32 LOD_2_SCREEN_COVERAGE = 0.40f;  std::set<LLPointer<LLHUDNameTag> > LLHUDNameTag::sTextObjects;  std::vector<LLPointer<LLHUDNameTag> > LLHUDNameTag::sVisibleTextObjects;  BOOL LLHUDNameTag::sDisplayText = TRUE ; +const F32 LLHUDNameTag::NAMETAG_MAX_WIDTH = 298.f; +const F32 LLHUDNameTag::HUD_TEXT_MAX_WIDTH = 190.f;  bool llhudnametag_further_away::operator()(const LLPointer<LLHUDNameTag>& lhs, const LLPointer<LLHUDNameTag>& rhs) const  { @@ -414,7 +415,8 @@ void LLHUDNameTag::addLine(const std::string &text_utf8,  						const LLColor4& color,  						const LLFontGL::StyleFlags style,  						const LLFontGL* font, -						const bool use_ellipses) +						const bool use_ellipses, +						F32 max_pixels)  {  	LLWString wline = utf8str_to_wstring(text_utf8);  	if (!wline.empty()) @@ -431,7 +433,7 @@ void LLHUDNameTag::addLine(const std::string &text_utf8,  		tokenizer tokens(wline, sep);  		tokenizer::iterator iter = tokens.begin(); -        const F32 max_pixels = HUD_TEXT_MAX_WIDTH; +        max_pixels = llmin(max_pixels, NAMETAG_MAX_WIDTH);          while (iter != tokens.end())          {              U32 line_length = 0; @@ -488,7 +490,7 @@ void LLHUDNameTag::setLabel(const std::string &label_utf8)  	addLabel(label_utf8);  } -void LLHUDNameTag::addLabel(const std::string& label_utf8) +void LLHUDNameTag::addLabel(const std::string& label_utf8, F32 max_pixels)  {  	LLWString wstr = utf8string_to_wstring(label_utf8);  	if (!wstr.empty()) @@ -502,13 +504,15 @@ void LLHUDNameTag::addLabel(const std::string& label_utf8)  		tokenizer tokens(wstr, sep);  		tokenizer::iterator iter = tokens.begin(); +        max_pixels = llmin(max_pixels, NAMETAG_MAX_WIDTH); +  		while (iter != tokens.end())  		{  			U32 line_length = 0;  			do	  			{  				S32 segment_length = mFontp->maxDrawableChars(iter->substr(line_length).c_str(),  -					HUD_TEXT_MAX_WIDTH, wstr.length(), LLFontGL::WORD_BOUNDARY_IF_POSSIBLE); +                    max_pixels, wstr.length(), LLFontGL::WORD_BOUNDARY_IF_POSSIBLE);  				LLHUDTextSegment segment(iter->substr(line_length, segment_length), LLFontGL::NORMAL, mColor, mFontp);  				mLabelSegments.push_back(segment);  				line_length += segment_length; @@ -695,7 +699,7 @@ void LLHUDNameTag::updateSize()  		const LLFontGL* fontp = iter->mFont;  		height += fontp->getLineHeight();  		height += LINE_PADDING; -		width = llmax(width, llmin(iter->getWidth(fontp), HUD_TEXT_MAX_WIDTH)); +		width = llmax(width, llmin(iter->getWidth(fontp), NAMETAG_MAX_WIDTH));  		++iter;  	} @@ -709,7 +713,7 @@ void LLHUDNameTag::updateSize()  	while (iter != mLabelSegments.end())  	{  		height += mFontp->getLineHeight(); -		width = llmax(width, llmin(iter->getWidth(mFontp), HUD_TEXT_MAX_WIDTH)); +		width = llmax(width, llmin(iter->getWidth(mFontp), NAMETAG_MAX_WIDTH));  		++iter;  	} diff --git a/indra/newview/llhudnametag.h b/indra/newview/llhudnametag.h index 7577dd5de6..361e4d4f4b 100644 --- a/indra/newview/llhudnametag.h +++ b/indra/newview/llhudnametag.h @@ -85,6 +85,9 @@ public:  		ALIGN_VERT_CENTER  	} EVertAlignment; +    static const F32 NAMETAG_MAX_WIDTH; // 298px, made to fit 31 M's +    static const F32 HUD_TEXT_MAX_WIDTH; // 190px +  public:  	// Set entire string, eliminating existing lines  	void setString(const std::string& text_utf8); @@ -92,11 +95,17 @@ public:  	void clearString();  	// Add text a line at a time, allowing custom formatting -	void addLine(const std::string &text_utf8, const LLColor4& color, const LLFontGL::StyleFlags style = LLFontGL::NORMAL, const LLFontGL* font = NULL, const bool use_ellipses = false); +	void addLine( +        const std::string &text_utf8, +        const LLColor4& color, +        const LLFontGL::StyleFlags style = LLFontGL::NORMAL, +        const LLFontGL* font = NULL, +        const bool use_ellipses = false, +        F32 max_pixels = HUD_TEXT_MAX_WIDTH);  	// For bubble chat, set the part above the chat text  	void setLabel(const std::string& label_utf8); -	void addLabel(const std::string& label_utf8); +	void addLabel(const std::string& label_utf8, F32 max_pixels = HUD_TEXT_MAX_WIDTH);  	// Sets the default font for lines with no font specified  	void setFont(const LLFontGL* font); diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index e6845127e3..3536b83989 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -453,7 +453,7 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,      BOOL is_friend = (LLAvatarTracker::instance().getBuddyInfo(from_id) == NULL) ? false : true;      BOOL accept_im_from_only_friend = gSavedPerAccountSettings.getBOOL("VoiceCallsFriendsOnly");      BOOL is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT && -        LLMuteList::getInstance()->isLinden(name); +        LLMuteList::isLinden(name);      chat.mMuted = is_muted;      chat.mFromID = from_id; @@ -521,7 +521,9 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,                      dialog,                      parent_estate_id,                      region_id, -                    position); +                    position, +                    false,      // is_region_msg +                    timestamp);                  if (!gIMMgr->isDNDMessageSend(session_id))                  { @@ -592,7 +594,8 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,                          parent_estate_id,                          region_id,                          position, -                        region_message); +                        region_message, +                        timestamp);                  }                  else                  { @@ -1111,7 +1114,9 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,                      IM_SESSION_INVITE,                      parent_estate_id,                      region_id, -                    position); +                    position, +                    false,      // is_region_msg +                    timestamp);              }              else              { @@ -1131,12 +1136,14 @@ void LLIMProcessing::processNewMessage(LLUUID from_id,                      from_id,                      name,                      buffer, -                    IM_OFFLINE == offline, -                    ll_safe_string((char*)binary_bucket), +                    (IM_OFFLINE == offline), +                    ll_safe_string((char*)binary_bucket),   // session name                      IM_SESSION_INVITE,                      parent_estate_id,                      region_id, -                    position); +                    position, +                    false,      // is_region_msg +                    timestamp);              }              break; @@ -1568,7 +1575,7 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url)          return;      } -    if (messages.emptyArray()) +    if (messages.size() == 0)      {          // Nothing to process          return; diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index bf9e226244..af16f5c7d4 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -1,25 +1,25 @@ -/**  +/**   * @file LLIMMgr.cpp   * @brief Container for Instant Messaging   *   * $LicenseInfo:firstyear=2001&license=viewerlgpl$   * Second Life Viewer Source Code   * Copyright (C) 2010, Linden Research, Inc. - *  + *   * This library is free software; you can redistribute it and/or   * modify it under the terms of the GNU Lesser General Public   * License as published by the Free Software Foundation;   * version 2.1 of the License only. - *  + *   * This library is distributed in the hope that it will be useful,   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   * Lesser General Public License for more details. - *  + *   * You should have received a copy of the GNU Lesser General Public   * License along with this library; if not, write to the Free Software   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  + *   * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA   * $/LicenseInfo$   */ @@ -41,6 +41,7 @@  #include "llstring.h"  #include "lltextutil.h"  #include "lltrans.h" +#include "lltranslate.h"  #include "lluictrlfactory.h"  #include "llfloaterimsessiontab.h"  #include "llagent.h" @@ -76,11 +77,17 @@ const static std::string ADHOC_NAME_SUFFIX(" Conference");  const static std::string NEARBY_P2P_BY_OTHER("nearby_P2P_by_other");  const static std::string NEARBY_P2P_BY_AGENT("nearby_P2P_by_agent"); +// Markers inserted around translated part of chat text +const static std::string XL8_START_TAG(" ("); +const static std::string XL8_END_TAG(")"); +const S32 XL8_PADDING = 3;  // XL8_START_TAG.size() + XL8_END_TAG.size() +  /** Timeout of outgoing session initialization (in seconds) */  const static U32 SESSION_INITIALIZATION_TIMEOUT = 30;  void startConfrenceCoro(std::string url, LLUUID tempSessionId, LLUUID creatorId, LLUUID otherParticipantId, LLSD agents);  void chatterBoxInvitationCoro(std::string url, LLUUID sessionId, LLIMMgr::EInvitationType invitationType); +void chatterBoxHistoryCoro(std::string url, LLUUID sessionId, std::string from, std::string message, U32 timestamp);  void start_deprecated_conference_chat(const LLUUID& temp_session_id, const LLUUID& creator_id, const LLUUID& other_participant_id, const LLSD& agents_to_invite);  const LLUUID LLOutgoingCallDialog::OCD_KEY = LLUUID("7CF78E11-0CFE-498D-ADB9-1417BF03DDB4"); @@ -111,7 +118,7 @@ void process_dnd_im(const LLSD& notification)      LLUUID sessionID = data["SESSION_ID"].asUUID();      LLUUID fromID = data["FROM_ID"].asUUID(); -    //re-create the IM session if needed  +    //re-create the IM session if needed      //(when coming out of DND mode upon app restart)      if(!gIMMgr->hasSession(sessionID))      { @@ -122,13 +129,13 @@ void process_dnd_im(const LLSD& notification)          {              name = av_name.getDisplayName();          } -		 -         -        LLIMModel::getInstance()->newSession(sessionID,  -            name,  -            IM_NOTHING_SPECIAL,  -            fromID,  -            false,  + + +        LLIMModel::getInstance()->newSession(sessionID, +            name, +            IM_NOTHING_SPECIAL, +            fromID, +            false,              false); //will need slight refactor to retrieve whether offline message or not (assume online for now)      } @@ -311,8 +318,8 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)  			}  			else  			{ -				if (is_dnd_msg && (ON_TOP == conversations_floater_status ||  -									NOT_ON_TOP == conversations_floater_status ||  +				if (is_dnd_msg && (ON_TOP == conversations_floater_status || +									NOT_ON_TOP == conversations_floater_status ||  									CLOSED == conversations_floater_status))  				{  					im_box->highlightConversationItemWidget(session_id, true); @@ -371,7 +378,7 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg)  	}  	if (store_dnd_message)  	{ -		// If in DND mode, allow notification to be stored so upon DND exit  +		// If in DND mode, allow notification to be stored so upon DND exit  		// the user will be notified with some limitations (see 'is_dnd_msg' flag checks)  		if(session_id.notNull()  			&& participant_id.notNull() @@ -392,7 +399,7 @@ void startConfrenceCoro(std::string url,  {      LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);      LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t -        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy)); +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("ConferenceChatStart", httpPolicy));      LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);      LLSD postData; @@ -432,7 +439,7 @@ void chatterBoxInvitationCoro(std::string url, LLUUID sessionId, LLIMMgr::EInvit  {      LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);      LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t -        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("TwitterConnect", httpPolicy)); +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("ConferenceInviteStart", httpPolicy));      LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);      LLSD postData; @@ -510,8 +517,124 @@ void chatterBoxInvitationCoro(std::string url, LLUUID sessionId, LLIMMgr::EInvit  } +void translateSuccess(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text, +                        U64 time_n_flags, std::string originalMsg, std::string expectLang, std::string translation, const std::string detected_language) +{ +    std::string message_txt(utf8_text); +    // filter out non-interesting responses +    if (!translation.empty() +        && ((detected_language.empty()) || (expectLang != detected_language)) +        && (LLStringUtil::compareInsensitive(translation, originalMsg) != 0)) +    {   // Note - if this format changes, also fix code in addMessagesFromServerHistory() +        message_txt += XL8_START_TAG + LLTranslate::removeNoTranslateTags(translation) + XL8_END_TAG; +    } -LLIMModel::LLIMModel()  +    // Extract info packed in time_n_flags +    bool log2file =      (bool)(time_n_flags & (1LL << 32)); +    bool is_region_msg = (bool)(time_n_flags & (1LL << 33)); +    U32 time_stamp = (U32)(time_n_flags & 0x00000000ffffffff); + +    LLIMModel::getInstance()->processAddingMessage(session_id, from, from_id, message_txt, log2file, is_region_msg, time_stamp); +} + +void translateFailure(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text, +                        U64 time_n_flags, int status, const std::string err_msg) +{ +    std::string message_txt(utf8_text); +    std::string msg = LLTrans::getString("TranslationFailed", LLSD().with("[REASON]", err_msg)); +    LLStringUtil::replaceString(msg, "\n", " "); // we want one-line error messages +    message_txt += XL8_START_TAG + msg + XL8_END_TAG; + +    // Extract info packed in time_n_flags +    bool log2file = (bool)(time_n_flags & (1LL << 32)); +    bool is_region_msg = (bool)(time_n_flags & (1LL << 33)); +    U32 time_stamp = (U32)(time_n_flags & 0x00000000ffffffff); + +    LLIMModel::getInstance()->processAddingMessage(session_id, from, from_id, message_txt, log2file, is_region_msg, time_stamp); +} + +void chatterBoxHistoryCoro(std::string url, LLUUID sessionId, std::string from, std::string message, U32 timestamp) +{   // if parameters from, message and timestamp have values, they are a message that opened chat +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("ChatHistory", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + +    LLSD postData; +    postData["method"] = "fetch history"; +    postData["session-id"] = sessionId; + +    LL_DEBUGS("ChatHistory") << sessionId << ": Chat history posting " << postData << " to " << url +        << ", from " << from << ", message " << message << ", timestamp " << (S32)timestamp << LL_ENDL; + +    LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData); + +    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +    if (!status) +    { +        LL_WARNS("ChatHistory") << sessionId << ": Bad HTTP response in chatterBoxHistoryCoro" +            << ", results: " << httpResults << LL_ENDL; +        return; +    } + +    // Add history to IM session +    LLSD history = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_CONTENT]; + +    LL_DEBUGS("ChatHistory") << sessionId << ": Chat server history fetch returned " << history << LL_ENDL; + +    try +    { +        LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(sessionId); +        if (session && history.isArray()) +        {   // Result array is sorted oldest to newest +            if (history.size() > 0) +            {   // History from the chat server has an integer 'time' value timestamp.   Create 'datetime' string which will match +                // what we have from the local history cache +                for (LLSD::array_iterator cur_server_hist = history.beginArray(), endLists = history.endArray(); +                    cur_server_hist != endLists; +                    cur_server_hist++) +                { +                    if ((*cur_server_hist).isMap()) +                    {   // Take the 'time' value from the server and make the date-time string that will be in local cache log files +                        //   {'from_id':u7aa8c222-8a81-450e-b3d1-9c28491ef717,'message':'Can you hear me now?','from':'Chat Tester','num':i86,'time':r1.66501e+09} +                        U32 timestamp = (U32)((*cur_server_hist)[LL_IM_TIME].asInteger()); +                        (*cur_server_hist)[LL_IM_DATE_TIME] = LLLogChat::timestamp2LogString(timestamp, true); +                    } +                } + +                session->addMessagesFromServerHistory(history, from, message, timestamp); + +                // Display the newly added messages +                LLFloaterIMSession* floater = LLFloaterReg::findTypedInstance<LLFloaterIMSession>("impanel", sessionId); +                if (floater && floater->isInVisibleChain()) +                { +                    floater->updateMessages(); +                } +            } +            else +            { +                LL_DEBUGS("ChatHistory") << sessionId << ": Empty history from chat server, nothing to add" << LL_ENDL; +            } +        } +        else if (session && !history.isArray()) +        { +            LL_WARNS("ChatHistory") << sessionId << ": Bad array data fetching chat history" << LL_ENDL; +        } +        else +        { +            LL_WARNS("ChatHistory") << sessionId << ": Unable to find session fetching chat history" << LL_ENDL; +        } +    } +    catch (...) +    { +        LOG_UNHANDLED_EXCEPTION("chatterBoxHistoryCoro"); +        LL_WARNS("ChatHistory") << "chatterBoxHistoryCoro unhandled exception while processing data for session " << sessionId << LL_ENDL; +    } +} + +LLIMModel::LLIMModel()  {  	addNewMsgCallback(boost::bind(&LLFloaterIMSession::newIMCallback, _1));  	addNewMsgCallback(boost::bind(&on_new_message, _1)); @@ -556,25 +679,25 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string&  		else  		{  			mSessionType = ADHOC_SESSION; -		}  +		}  	}  	if(mVoiceChannel)  	{  		mVoiceChannelStateChangeConnection = mVoiceChannel->setStateChangedCallback(boost::bind(&LLIMSession::onVoiceChannelStateChanged, this, _1, _2, _3));  	} -		 +  	mSpeakers = new LLIMSpeakerMgr(mVoiceChannel);  	// All participants will be added to the list of people we've recently interacted with. -	// we need to add only _active_ speakers...so comment this.  +	// we need to add only _active_ speakers...so comment this.  	// may delete this later on cleanup  	//mSpeakers->addListener(&LLRecentPeople::instance(), "add");  	//we need to wait for session initialization for outgoing ad-hoc and group chat session  	//correct session id for initiated ad-hoc chat will be received from the server -	if (!LLIMModel::getInstance()->sendStartSession(mSessionID, mOtherParticipantID,  +	if (!LLIMModel::getInstance()->sendStartSession(mSessionID, mOtherParticipantID,  		mInitialTargetIDs, mType))  	{  		//we don't need to wait for any responses @@ -656,7 +779,7 @@ void LLIMModel::LLIMSession::onVoiceChannelStateChanged(const LLVoiceChannel::ES  					LLStringUtil::format_map_t string_args;  					string_args["[NAME]"] = other_avatar_name;  					message = LLTrans::getString("name_started_call", string_args); -					LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, message);				 +					LLIMModel::getInstance()->addMessage(mSessionID, SYSTEM_FROM, LLUUID::null, message);  					break;  				}  			case LLVoiceChannel::STATE_CONNECTED : @@ -760,14 +883,21 @@ void LLIMModel::LLIMSession::sessionInitReplyReceived(const LLUUID& new_session_  	}  } -void LLIMModel::LLIMSession::addMessage(const std::string& from, const LLUUID& from_id, const std::string& utf8_text, const std::string& time, const bool is_history, bool is_region_msg) +void LLIMModel::LLIMSession::addMessage(const std::string& from, +                                        const LLUUID& from_id, +                                        const std::string& utf8_text, +                                        const std::string& time, +                                        const bool is_history,  // comes from a history file or chat server +                                        const bool is_region_msg, +                                        const U32 timestamp)   // may be zero  {  	LLSD message;  	message["from"] = from;  	message["from_id"] = from_id;  	message["message"] = utf8_text; -	message["time"] = time;  -	message["index"] = (LLSD::Integer)mMsgs.size();  +	message["time"] = time;         // string used in display, may be full data YYYY/MM/DD HH:MM or just HH:MM +    message["timestamp"] = (S32)timestamp;          // use string? LLLogChat::timestamp2LogString(timestamp, true); +	message["index"] = (LLSD::Integer)mMsgs.size();  	message["is_history"] = is_history;  	message["is_region_msg"] = is_region_msg; @@ -788,7 +918,7 @@ void LLIMModel::LLIMSession::addMessage(const std::string& from, const LLUUID& f  		}  	} -	mMsgs.push_front(message);  +	mMsgs.push_front(message);          // Add most recent messages to the front of mMsgs  	if (mSpeakers && from_id.notNull())  	{ @@ -797,35 +927,281 @@ void LLIMModel::LLIMSession::addMessage(const std::string& from, const LLUUID& f  	}  } -void LLIMModel::LLIMSession::addMessagesFromHistory(const std::list<LLSD>& history) +void LLIMModel::LLIMSession::addMessagesFromHistoryCache(const chat_message_list_t& history)  { -	std::list<LLSD>::const_iterator it = history.begin(); -	while (it != history.end()) -	{ -		const LLSD& msg = *it; +    // Add the messages from the local cached chat history to the session window +    for (const auto& msg : history) +    { +        std::string from = msg[LL_IM_FROM]; +        LLUUID from_id; +        if (msg[LL_IM_FROM_ID].isDefined()) +        { +            from_id = msg[LL_IM_FROM_ID].asUUID(); +        } +        else +        {   // convert it to a legacy name if we have a complete name +            std::string legacy_name = gCacheName->buildLegacyName(from); +            from_id = LLAvatarNameCache::getInstance()->findIdByName(legacy_name); +        } -		std::string from = msg[LL_IM_FROM]; -		LLUUID from_id; -		if (msg[LL_IM_FROM_ID].isDefined()) -		{ -			from_id = msg[LL_IM_FROM_ID].asUUID(); -		} -		else -		{ -			// convert it to a legacy name if we have a complete name -			std::string legacy_name = gCacheName->buildLegacyName(from); -			from_id = LLAvatarNameCache::getInstance()->findIdByName(legacy_name); -		} +        // Save the last minute of messages so we can merge with the chat server history. +        // Really would be nice to have a numeric timestamp in the local cached chat file +        const std::string & msg_time_str = msg[LL_IM_DATE_TIME].asString(); +        if (mLastHistoryCacheDateTime != msg_time_str) +        { +            mLastHistoryCacheDateTime = msg_time_str;   // Reset to the new time +            mLastHistoryCacheMsgs.clear(); +        } +        mLastHistoryCacheMsgs.push_front(msg); +        LL_DEBUGS("ChatHistory") << mSessionID << ": Adding history cache message: " << msg << LL_ENDL; -		std::string timestamp = msg[LL_IM_TIME]; -		std::string text = msg[LL_IM_TEXT]; +        // Add message from history cache to the display +        addMessage(from, from_id, msg[LL_IM_TEXT], msg[LL_IM_TIME], true, false, 0);   // from history data, not region message, no timestamp +    } +} -		addMessage(from, from_id, text, timestamp, true); +void LLIMModel::LLIMSession::addMessagesFromServerHistory(const LLSD& history,             // Array of chat messages from chat server +                                                        const std::string& target_from,    // Sender of message that opened chat +                                                        const std::string& target_message, // Message text that opened chat +                                                        U32 timestamp)                     // timestamp of message that opened chat +{   // Add messages from history returned by the chat server. + +    // The session mMsgs may contain chat messages from the local history cache file, and possibly one or more newly +    // arrived chat messages.   If the chat window was manually opened, these will be empty and history can +    // more easily merged.    The history from the server, however, may overlap what is in the file and those must also be merged. + +    // At this point, the session mMsgs can have +    //   no messages +    //   nothing from history file cache, but one or more very recently arrived messages, +    //   messages from history file cache, no recent chat +    //   messages from history file cache, one or more very recent messages +    // +    // The chat history from server can possibly contain: +    //   no messages +    //   messages that start back before anything in the local file (obscure case, but possible) +    //   messages that match messages from the history file cache +    //   messages from the last hour, new to the viewer +    //   one or more messages that match most recently received chat (the one that opened the window) +    // In other words: +    //   messages from chat server may or may not match what we already have in mMsgs +    //   We can drop anything that is during the time span covered by the local cache file +    //   To keep things simple, drop any chat data older than the local cache file + +    if (!history.isArray()) +    { +        LL_WARNS("ChatHistory") << mSessionID << ": Unexpected history data not array, type " << (S32)history.type() << LL_ENDL; +        return; +    } -		it++; -	} +    if (history.size() == 0) +    {   // If history is empty +        LL_DEBUGS("ChatHistory") << mSessionID << ": addMessagesFromServerHistory() has empty history, nothing to merge" << LL_ENDL; +        return; +    } + +    if (history.size() == 1 &&          // Server chat history has one entry, +        target_from.length() > 0 &&     // and we have a chat message that just arrived +        mMsgs.size() > 0)               // and we have some data in the window - assume the history message is there. +    {   // This is the common case where a group chat is silent for a while, and then one message is sent. +        LL_DEBUGS("ChatHistory") << mSessionID << ": addMessagesFromServerHistory() only has chat message just received." << LL_ENDL; +        return; +    } + +    LL_DEBUGS("ChatHistory") << mSessionID << ": addMessagesFromServerHistory() starting with mMsg.size() " << mMsgs.size() +        << " adding history with " << history.size() << " messages" +        << ", target_from: " << target_from +        << ", target_message: " << target_message +        << ", timestamp: " << (S32)timestamp << LL_ENDL; + +    // At start of merging, mMsgs is either empty, has some chat messages read from a local cache file, and may have +    // one or more messages that just arrived from the server. +    U32 match_timestamp = 0; +    chat_message_list_t shift_msgs; +    if (mMsgs.size() > 0 && +        target_from.length() > 0 +        && target_message.length() > 0) +    {   // Find where to insert the history messages by popping off a few in the session. +        // The most common case is one duplciate message, the one that opens a chat session +        while (mMsgs.size() > 0) +        { +            // The "time" value from mMsgs is a string, either just time HH:MM or a full date and time +            LLSD cur_msg = mMsgs.front();       // Get most recent message from the chat display (front of mMsgs list) + +            if (cur_msg.isMap()) +            { +                LL_DEBUGS("ChatHistoryCompare") << mSessionID << ": Finding insertion point, looking at cur_msg: " << cur_msg << LL_ENDL; + +                match_timestamp = cur_msg["timestamp"].asInteger();  // get timestamp of message in the session, may be zero +                if ((S32)timestamp > match_timestamp) +                { +                    LL_DEBUGS("ChatHistory") << mSessionID << ": found older chat message: " << cur_msg +                        << ", timestamp " << (S32)timestamp +                        << " vs. match_timestamp " << match_timestamp +                        << ", shift_msgs size is " << shift_msgs.size() << LL_ENDL; +                    break; +                } +                // Have the matching message or one more recent: these need to be at the end +                shift_msgs.push_front(cur_msg);     // Move chat message to temp list. +                mMsgs.pop_front();                  // Normally this is just one message +                LL_DEBUGS("ChatHistory") << mSessionID << ": shifting chat message " << cur_msg +                    << " to be inserted at end, shift_msgs size is " << shift_msgs.size() +                    << ", match_timestamp " << match_timestamp +                    << ", timestamp " << (S32)timestamp << LL_ENDL; +            } +            else +            { +                LL_DEBUGS("ChatHistory") << mSessionID << ": Unexpected non-map entry in session messages: " << cur_msg << LL_ENDL; +                return; +            } +        } +    } + +    // Now merge messages from server history data into the session display.   The history data +    // from the local file may overlap with the chat messages from the server. +    // Drop any messages from the chat server history that are before the latest one from the local history file. +    // Unfortunately, messages from the local file don't have timestamps - just datetime strings +    LLSD::array_const_iterator cur_history_iter = history.beginArray(); +    while (cur_history_iter != history.endArray()) +    { +        const LLSD &cur_server_hist = *cur_history_iter; +        cur_history_iter++; + +        if (cur_server_hist.isMap()) +        {   // Each server history entry looks like +            //   { 'from':'Laggy Avatar', 'from_id' : u72345678 - 744f - 43b9 - 98af - b06f1c76ddda, 'index' : i24, 'is_history' : 1, 'message' : 'That was slow', 'time' : '02/13/2023 10:03', 'timestamp' : i1676311419 } + +            // If we reach the message that opened our window, stop adding messages +            U32 history_msg_timestamp = (U32)cur_server_hist[LL_IM_TIME].asInteger(); +            if ((match_timestamp > 0 && match_timestamp <= history_msg_timestamp) || +                (timestamp > 0 && timestamp <= history_msg_timestamp)) +            {   // we found the message we matched, so stop inserting from chat server history +                LL_DEBUGS("ChatHistoryCompare") << "Found end of chat history insertion with match_timestamp " << (S32)match_timestamp +                    << " vs. history_msg_timestamp " << (S32)history_msg_timestamp +                    << " vs. timestamp " << (S32)timestamp +                    << LL_ENDL; +                break; +            } +            LL_DEBUGS("ChatHistoryCompare") << "Compared match_timestamp " << (S32)match_timestamp +                << " vs. history_msg_timestamp " << (S32)history_msg_timestamp << LL_ENDL; + +            bool add_chat_to_conversation = true; +            if (!mLastHistoryCacheDateTime.empty()) +            {   // Skip past the any from server that are older than what we already read from the history file. +                std::string history_datetime = cur_server_hist[LL_IM_DATE_TIME].asString(); +                if (history_datetime.empty()) +                { +                    history_datetime = cur_server_hist[LL_IM_TIME].asString(); +                } + +                if (history_datetime < mLastHistoryCacheDateTime) +                { +                    LL_DEBUGS("ChatHistoryCompare") << "Skipping message from chat server history since it's older than messages the session already has." +                        << history_datetime << " vs  " << mLastHistoryCacheDateTime << LL_ENDL; +                    add_chat_to_conversation = false; +                } +                else if (history_datetime > mLastHistoryCacheDateTime) +                {   // The message from the chat server is more recent than the last one from the local cache file.   Add it +                    LL_DEBUGS("ChatHistoryCompare") << "Found message dated " +                        << history_datetime << " vs " << mLastHistoryCacheDateTime +                        << ", adding new message from chat server history " << cur_server_hist << LL_ENDL; +                } +                else   // (history_datetime == mLastHistoryCacheDateTime) +                {      // Messages are in the same minute as the last from the cache log file. +                    const std::string & history_msg_text = cur_server_hist[LL_IM_TEXT]; + +                    // Look in the saved messages from the history file that have the same time +                    for (const auto& scan_msg : mLastHistoryCacheMsgs) +                    { +                        LL_DEBUGS("ChatHistoryCompare") << "comparing messages " << scan_msg[LL_IM_TEXT] +                            << " with " << cur_server_hist << LL_ENDL; +                        if (scan_msg.size() > 0) +                        {   // Extra work ... the history_msg_text value may have been translated, i.e. "I am confused (je suis confus)" +                            //  while the server history will only have the first part "I am confused" +                            std::string target_compare(scan_msg[LL_IM_TEXT]); +                            if (target_compare.size() > history_msg_text.size() + XL8_PADDING && +                                target_compare.substr(history_msg_text.size(), XL8_START_TAG.size()) == XL8_START_TAG && +                                target_compare.substr(target_compare.size() - XL8_END_TAG.size()) == XL8_END_TAG) +                            {   // This really looks like a "translated string (cadena traducida)" so just compare the source part +                                LL_DEBUGS("ChatHistory") << mSessionID << ": Found translated chat " << target_compare +                                    << " when comparing to history " << history_msg_text +                                    << ", will truncate" << LL_ENDL; +                                target_compare = target_compare.substr(0, history_msg_text.size()); +                            } +                            if (history_msg_text == target_compare) +                            {   // Found a match, so don't add a duplicate chat message to the window +                                LL_DEBUGS("ChatHistory") << mSessionID << ": Found duplicate message text " << history_msg_text +                                    << " : " << (S32)history_msg_timestamp << ", matching datetime " << history_datetime << LL_ENDL; +                                add_chat_to_conversation = false; +                                break; +                            } +                        } +                    } +                } +            } + +            LLUUID sender_id = cur_server_hist[LL_IM_FROM_ID].asUUID(); +            if (add_chat_to_conversation) +            {   // Check if they're muted +                if (LLMuteList::getInstance()->isMuted(sender_id, LLMute::flagTextChat)) +                { +                    add_chat_to_conversation = false; +                    LL_DEBUGS("ChatHistory") << mSessionID << ": Skipped adding chat from " << sender_id +                        << " as muted, message: " << cur_server_hist +                        << LL_ENDL; +                } +            } + +            if (add_chat_to_conversation) +            {   // Finally add message to the chat session +                std::string chat_time_str = LLConversation::createTimestamp((U64Seconds)history_msg_timestamp); +                std::string sender_name = cur_server_hist[LL_IM_FROM].asString(); + +                std::string history_msg_text = cur_server_hist[LL_IM_TEXT].asString(); +                LLSD message; +                message["from"] = sender_name; +                message["from_id"] = sender_id; +                message["message"] = history_msg_text; +                message["time"] = chat_time_str; +                message["timestamp"] = (S32)history_msg_timestamp; +                message["index"] = (LLSD::Integer)mMsgs.size(); +                message["is_history"] = true; +                mMsgs.push_front(message); + +                LL_DEBUGS("ChatHistory") << mSessionID << ": push_front() adding group chat history message " << message << LL_ENDL; + +                // Add chat history messages to the local cache file, only in the case where we opened the chat window +                // Need to solve the logic around messages that arrive and open chat - at this point, they've already been added to the +                //   local history cache file.   If we append messages here, it will be out of order. +                if (target_from.empty() && target_message.empty()) +                { +                    LLIMModel::getInstance()->logToFile(LLIMModel::getInstance()->getHistoryFileName(mSessionID), +                        sender_name, sender_id, history_msg_text); +                } +            } +        } +    } + +    S32 shifted_size = shift_msgs.size(); +    while (shift_msgs.size() > 0) +    {   // Finally add back any new messages, and tweak the index value to be correct. +        LLSD newer_message = shift_msgs.front(); +        shift_msgs.pop_front(); +        S32 old_index = newer_message["index"]; +        newer_message["index"] = (LLSD::Integer)mMsgs.size();   // Update the index to match the new position in the conversation +        LL_DEBUGS("ChatHistory") << mSessionID << ": Re-adding newest group chat history messages from " << newer_message["from"] +            << ", text: " << newer_message["message"] +            << " old index " << old_index << ", new index " << newer_message["index"] << LL_ENDL; +        mMsgs.push_front(newer_message); +    } + +    LL_DEBUGS("ChatHistory") << mSessionID << ": addMessagesFromServerHistory() exiting with mMsg.size() " << mMsgs.size() +        << ", shifted " << shifted_size << " messages" << LL_ENDL; + +    mLastHistoryCacheDateTime.clear();  // Don't need this data +    mLastHistoryCacheMsgs.clear();  } +  void LLIMModel::LLIMSession::chatFromLogFile(LLLogChat::ELogLineType type, const LLSD& msg, void* userdata)  {  	if (!userdata) return; @@ -834,26 +1210,29 @@ void LLIMModel::LLIMSession::chatFromLogFile(LLLogChat::ELogLineType type, const  	if (type == LLLogChat::LOG_LINE)  	{ -		self->addMessage("", LLSD(), msg["message"].asString(), "", true); +        LL_DEBUGS("ChatHistory") << "chatFromLogFile() adding LOG_LINE message from " << msg << LL_ENDL; +        self->addMessage("", LLSD(), msg["message"].asString(), "", true, false, 0);        // from history data, not region message, no timestamp  	}  	else if (type == LLLogChat::LOG_LLSD)  	{ -		self->addMessage(msg["from"].asString(), msg["from_id"].asUUID(), msg["message"].asString(), msg["time"].asString(), true); +        LL_DEBUGS("ChatHistory") << "chatFromLogFile() adding LOG_LLSD message from " << msg << LL_ENDL; +        self->addMessage(msg["from"].asString(), msg["from_id"].asUUID(), msg["message"].asString(), msg["time"].asString(), true, false, 0);  // from history data, not region message, no timestamp  	}  }  void LLIMModel::LLIMSession::loadHistory()  {  	mMsgs.clear(); +    mLastHistoryCacheMsgs.clear(); +    mLastHistoryCacheDateTime.clear();  	if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") )  	{ -		std::list<LLSD> chat_history; - -		//involves parsing of a chat history +        // read and parse chat history from local file +        chat_message_list_t chat_history;  		LLLogChat::loadChatHistory(mHistoryFileName, chat_history, LLSD(), isGroupChat()); -		addMessagesFromHistory(chat_history); -	} +        addMessagesFromHistoryCache(chat_history); +    }  }  LLIMModel::LLIMSession* LLIMModel::findIMSession(const LLUUID& session_id) const @@ -873,7 +1252,7 @@ LLIMModel::LLIMSession* LLIMModel::findAdHocIMSession(const uuid_vec_t& ids)  	for (; it != mId2SessionMap.end(); ++it)  	{  		LLIMSession* session = (*it).second; -	 +  		if (!session->isAdHoc()) continue;  		if (session->mInitialTargetIDs.size() != num) continue; @@ -884,8 +1263,8 @@ LLIMModel::LLIMSession* LLIMModel::findAdHocIMSession(const uuid_vec_t& ids)  		{  			tmp_list.remove(*iter);  			++iter; -			 -			if (tmp_list.empty())  + +			if (tmp_list.empty())  			{  				break;  			} @@ -941,7 +1320,7 @@ void LLIMModel::LLIMSession::buildHistoryFileName()  	if (isAdHoc())  	{  		/* in case of outgoing ad-hoc sessions we need to make specilized names -		* if this naming system is ever changed then the filtering definitions in  +		* if this naming system is ever changed then the filtering definitions in  		* lllogchat.cpp need to be change acordingly so that the filtering for the  		* date stamp code introduced in STORM-102 will work properly and not add  		* a date stamp to the Ad-hoc conferences. @@ -954,7 +1333,7 @@ void LLIMModel::LLIMSession::buildHistoryFileName()  		else  		{  			//in case of incoming ad-hoc sessions -			mHistoryFileName = mName + " " + LLLogChat::timestamp(true) + " " + mSessionID.asString().substr(0, 4); +			mHistoryFileName = mName + " " + LLLogChat::timestamp2LogString(0, true) + " " + mSessionID.asString().substr(0, 4);  		}  	}  	else if (isP2P()) // look up username to use as the log name @@ -985,7 +1364,7 @@ void LLIMModel::LLIMSession::buildHistoryFileName()  LLUUID LLIMModel::LLIMSession::generateHash(const std::set<LLUUID>& sorted_uuids)  {  	LLMD5 md5_uuid; -	 +  	std::set<LLUUID>::const_iterator it = sorted_uuids.begin();  	while (it != sorted_uuids.end())  	{ @@ -1047,7 +1426,7 @@ void LLIMModel::testMessages()  	S32 rand1 = ll_rand(sizeof firstname)/(sizeof firstname[0]);  	S32 rand2 = ll_rand(sizeof lastname)/(sizeof lastname[0]); -	 +  	from = firstname[rand1] + " " + lastname[rand2];  	bot2_id.generate(from);  	LLUUID bot2_session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, bot2_id); @@ -1057,7 +1436,7 @@ void LLIMModel::testMessages()  }  //session name should not be empty -bool LLIMModel::newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type,  +bool LLIMModel::newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type,  						   const LLUUID& other_participant_id, const uuid_vec_t& ids, bool voice, bool has_offline_msg)  {  	if (name.empty()) @@ -1099,7 +1478,7 @@ bool LLIMModel::clearSession(const LLUUID& session_id)  	return true;  } -void LLIMModel::getMessages(const LLUUID& session_id, std::list<LLSD>& messages, int start_index, const bool sendNoUnreadMsgs) +void LLIMModel::getMessages(const LLUUID& session_id, chat_message_list_t& messages, int start_index, const bool sendNoUnreadMsgs)  {  	getMessagesSilently(session_id, messages, start_index); @@ -1109,7 +1488,7 @@ void LLIMModel::getMessages(const LLUUID& session_id, std::list<LLSD>& messages,  	}  } -void LLIMModel::getMessagesSilently(const LLUUID& session_id, std::list<LLSD>& messages, int start_index) +void LLIMModel::getMessagesSilently(const LLUUID& session_id, chat_message_list_t& messages, int start_index)  {  	LLIMSession* session = findIMSession(session_id);  	if (!session) @@ -1120,7 +1499,7 @@ void LLIMModel::getMessagesSilently(const LLUUID& session_id, std::list<LLSD>& m  	int i = session->mMsgs.size() - start_index; -	for (std::list<LLSD>::iterator iter = session->mMsgs.begin(); +	for (chat_message_list_t::iterator iter = session->mMsgs.begin();  		iter != session->mMsgs.end() && i > 0;  		iter++)  	{ @@ -1142,7 +1521,7 @@ void LLIMModel::sendNoUnreadMessages(const LLUUID& session_id)  	session->mNumUnread = 0;  	session->mParticipantUnreadMessageCount = 0; -	 +  	LLSD arg;  	arg["session_id"] = session_id;  	arg["num_unread"] = 0; @@ -1150,17 +1529,23 @@ void LLIMModel::sendNoUnreadMessages(const LLUUID& session_id)  	mNoUnreadMsgsSignal(arg);  } -bool LLIMModel::addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text, bool is_region_msg) { -	 +bool LLIMModel::addToHistory(const LLUUID& session_id, +                             const std::string& from, +                             const LLUUID& from_id, +                             const std::string& utf8_text, +                             bool is_region_msg, +                             U32 timestamp) +{  	LLIMSession* session = findIMSession(session_id); -	if (!session)  +	if (!session)  	{  		LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL;  		return false;  	} -	session->addMessage(from, from_id, utf8_text, LLLogChat::timestamp(false), false, is_region_msg); //might want to add date separately +    // This is where a normal arriving message is added to the session.   Note that the time string created here is without the full date +	session->addMessage(from, from_id, utf8_text, LLLogChat::timestamp2LogString(timestamp, false), false, is_region_msg, timestamp);  	return true;  } @@ -1168,14 +1553,14 @@ bool LLIMModel::addToHistory(const LLUUID& session_id, const std::string& from,  bool LLIMModel::logToFile(const std::string& file_name, const std::string& from, const LLUUID& from_id, const std::string& utf8_text)  {  	if (gSavedPerAccountSettings.getS32("KeepConversationLogTranscripts") > 1) -	{	 +	{  		std::string from_name = from;  		LLAvatarName av_name; -		if (!from_id.isNull() &&  +		if (!from_id.isNull() &&  			LLAvatarNameCache::get(from_id, &av_name) &&  			!av_name.isDisplayNameDefault()) -		{	 +		{  			from_name = av_name.getCompleteName();  		} @@ -1189,43 +1574,63 @@ bool LLIMModel::logToFile(const std::string& file_name, const std::string& from,  	}  } -bool LLIMModel::proccessOnlineOfflineNotification( -	const LLUUID& session_id,  -	const std::string& utf8_text) +void LLIMModel::proccessOnlineOfflineNotification( +	const LLUUID& session_id, +    const std::string& utf8_text)  {  	// Add system message to history -	return addMessage(session_id, SYSTEM_FROM, LLUUID::null, utf8_text); +	addMessage(session_id, SYSTEM_FROM, LLUUID::null, utf8_text);  } -bool LLIMModel::addMessage(const LLUUID& session_id, const std::string& from, const LLUUID& from_id,  -						   const std::string& utf8_text, bool log2file, bool is_region_msg) {  +void LLIMModel::addMessage(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, +						   const std::string& utf8_text, bool log2file /* = true */, bool is_region_msg, /* = false */ U32 time_stamp /* = 0 */) +{ +    if (gSavedSettings.getBOOL("TranslateChat") && (from != SYSTEM_FROM)) +    { +        const std::string from_lang = ""; // leave empty to trigger autodetect +        const std::string to_lang = LLTranslate::getTranslateLanguage(); +        U64 time_n_flags = ((U64) time_stamp) | (log2file ? (1LL << 32) : 0) | (is_region_msg ? (1LL << 33) : 0);   // boost::bind has limited parameters +        LLTranslate::translateMessage(from_lang, to_lang, utf8_text, +            boost::bind(&translateSuccess, session_id, from, from_id, utf8_text, time_n_flags, utf8_text, from_lang, _1, _2), +            boost::bind(&translateFailure, session_id, from, from_id, utf8_text, time_n_flags, _1, _2)); +    } +    else +    { +        processAddingMessage(session_id, from, from_id, utf8_text, log2file, is_region_msg, time_stamp); +    } +} -	LLIMSession* session = addMessageSilently(session_id, from, from_id, utf8_text, log2file, is_region_msg); -	if (!session) return false; +void LLIMModel::processAddingMessage(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, +    const std::string& utf8_text, bool log2file, bool is_region_msg, U32 time_stamp) +{ +    LLIMSession* session = addMessageSilently(session_id, from, from_id, utf8_text, log2file, is_region_msg, time_stamp); +    if (!session) +        return; -	//good place to add some1 to recent list -	//other places may be called from message history. -	if( !from_id.isNull() && -		( session->isP2PSessionType() || session->isAdHocSessionType() ) ) -		LLRecentPeople::instance().add(from_id); +    //good place to add some1 to recent list +    //other places may be called from message history. +    if( !from_id.isNull() && +        ( session->isP2PSessionType() || session->isAdHocSessionType() ) ) +        LLRecentPeople::instance().add(from_id); -	// notify listeners -	LLSD arg; -	arg["session_id"] = session_id; -	arg["num_unread"] = session->mNumUnread; -	arg["participant_unread"] = session->mParticipantUnreadMessageCount; -	arg["message"] = utf8_text; -	arg["from"] = from; -	arg["from_id"] = from_id; -	arg["time"] = LLLogChat::timestamp(false); -	arg["session_type"] = session->mSessionType; -	mNewMsgSignal(arg); +    // notify listeners +    LLSD arg; +    arg["session_id"] = session_id; +    arg["num_unread"] = session->mNumUnread; +    arg["participant_unread"] = session->mParticipantUnreadMessageCount; +    arg["message"] = utf8_text; +    arg["from"] = from; +    arg["from_id"] = from_id; +    arg["time"] = LLLogChat::timestamp2LogString(time_stamp, true); +    arg["session_type"] = session->mSessionType; +    arg["is_region_msg"] = is_region_msg; -	return true; +    mNewMsgSignal(arg);  } -LLIMModel::LLIMSession* LLIMModel::addMessageSilently(const LLUUID& session_id, const std::string& from, const LLUUID& from_id,  -													 const std::string& utf8_text, bool log2file, bool is_region_msg) +LLIMModel::LLIMSession* LLIMModel::addMessageSilently(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, +													  const std::string& utf8_text, bool log2file /* = true */, bool is_region_msg, /* false */ +                                                      U32 timestamp /* = 0 */)  {  	LLIMSession* session = findIMSession(session_id); @@ -1241,12 +1646,12 @@ LLIMModel::LLIMSession* LLIMModel::addMessageSilently(const LLUUID& session_id,  		from_name = SYSTEM_FROM;  	} -	addToHistory(session_id, from_name, from_id, utf8_text, is_region_msg); +	addToHistory(session_id, from_name, from_id, utf8_text, is_region_msg, timestamp);  	if (log2file)  	{  		logToFile(getHistoryFileName(session_id), from_name, from_id, utf8_text);  	} -	 +  	session->mNumUnread++;  	//update count of unread messages from real participant @@ -1348,7 +1753,7 @@ const std::string& LLIMModel::getHistoryFileName(const LLUUID& session_id) const  // TODO get rid of other participant ID -void LLIMModel::sendTypingState(LLUUID session_id, LLUUID other_participant_id, BOOL typing)  +void LLIMModel::sendTypingState(LLUUID session_id, LLUUID other_participant_id, BOOL typing)  {  	std::string name;  	LLAgentUI::buildFullname(name); @@ -1379,7 +1784,7 @@ void LLIMModel::sendLeaveSession(const LLUUID& session_id, const LLUUID& other_p  			FALSE,  			gAgent.getSessionID(),  			other_participant_id, -			name,  +			name,  			LLStringUtil::null,  			IM_ONLINE,  			IM_SESSION_LEAVE, @@ -1400,7 +1805,7 @@ void LLIMModel::sendMessage(const std::string& utf8_text,  	const LLRelationship* info = NULL;  	info = LLAvatarTracker::instance().getBuddyInfo(other_participant_id); -	 +  	U8 offline = (!info || info->isOnline()) ? IM_ONLINE : IM_OFFLINE;  	// Old call to send messages to SLim client,  no longer supported.  	//if((offline == IM_OFFLINE) && (LLVoiceClient::getInstance()->isOnlineSIP(other_participant_id))) @@ -1408,7 +1813,7 @@ void LLIMModel::sendMessage(const std::string& utf8_text,  	//	// User is online through the OOW connector, but not with a regular viewer.  Try to send the message via SLVoice.  	//	sent = LLVoiceClient::getInstance()->sendTextMessage(other_participant_id, utf8_text);  	//} -	 +  	if(!sent)  	{  		// Send message normally. @@ -1465,7 +1870,7 @@ void LLIMModel::sendMessage(const std::string& utf8_text,  		}  	} -	if((dialog == IM_NOTHING_SPECIAL) &&  +	if((dialog == IM_NOTHING_SPECIAL) &&  	   (other_participant_id.notNull()))  	{  		// Do we have to replace the /me's here? @@ -1503,7 +1908,7 @@ void LLIMModel::sendMessage(const std::string& utf8_text,  		// to Recent People to prevent showing of an item with (?? ?)(?? ?), sans the spaces. See EXT-8246.  		// Concrete participants will be added into this list once they sent message in chat.  		if (IM_SESSION_INVITE == dialog) return; -			 +  		if (IM_SESSION_CONFERENCE_START == dialog) // outgoing ad-hoc session  		{  			// Add only online members of conference to recent list (EXT-8658) @@ -1585,7 +1990,7 @@ void start_deprecated_conference_chat(  	for(S32 i = 0; i < count; ++i)  	{  		LLUUID agent_id = agents_to_invite[i].asUUID(); -		 +  		memcpy(pos, &agent_id, UUID_BYTES);  		pos += UUID_BYTES;  	} @@ -1601,7 +2006,7 @@ void start_deprecated_conference_chat(  		bucket_size);  	gAgent.sendReliableMessage(); -  +  	delete[] bucket;  } @@ -1822,7 +2227,7 @@ void LLCallDialogManager::onVoiceChannelChangedInt(const LLUUID &session_id)  {  	LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id);  	if(!session) -	{		 +	{  		mPreviousSessionlName = mCurrentSessionlName;  		mCurrentSessionlName = ""; // Empty string results in "Nearby Voice Chat" after substitution  		return; @@ -1845,7 +2250,7 @@ void LLCallDialogManager::onVoiceChannelChangedInt(const LLUUID &session_id)  	if (LLVoiceChannel::getCurrentVoiceChannel()->getState() == LLVoiceChannel::STATE_CALL_STARTED &&  		LLVoiceChannel::getCurrentVoiceChannel()->getCallDirection() == LLVoiceChannel::OUTGOING_CALL)  	{ -		 +  		//*TODO get rid of duplicated code  		LLSD mCallDialogPayload;  		mCallDialogPayload["session_id"] = mSession->mSessionID; @@ -1860,7 +2265,7 @@ void LLCallDialogManager::onVoiceChannelChangedInt(const LLUUID &session_id)  		if(ocd)  		{  			ocd->show(mCallDialogPayload); -		}	 +		}  	}  } @@ -1893,7 +2298,7 @@ void LLCallDialogManager::onVoiceChannelStateChangedInt(const LLVoiceChannel::ES  	mCallDialogPayload["ended_by_agent"] = ended_by_agent;  	switch(new_state) -	{			 +	{  	case LLVoiceChannel::STATE_CALL_STARTED :  		// do not show "Calling to..." if it is incoming call  		if(direction == LLVoiceChannel::INCOMING_CALL) @@ -1922,7 +2327,7 @@ void LLCallDialogManager::onVoiceChannelStateChangedInt(const LLVoiceChannel::ES  	if(ocd)  	{  		ocd->show(mCallDialogPayload); -	}	 +	}  }  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1948,9 +2353,9 @@ BOOL LLCallDialog::postBuild()  {  	if (!LLDockableFloater::postBuild() || !gToolBarView)  		return FALSE; -	 +  	dockToToolbarButton("speak"); -	 +  	return TRUE;  } @@ -1968,20 +2373,20 @@ LLDockControl::DocAt LLCallDialog::getDockControlPos(const std::string& toolbarB  {  	LLCommandId command_id(toolbarButtonName);  	S32 toolbar_loc = gToolBarView->hasCommand(command_id); -	 +  	LLDockControl::DocAt doc_at = LLDockControl::TOP; -	 +  	switch (toolbar_loc)  	{  		case LLToolBarEnums::TOOLBAR_LEFT:  			doc_at = LLDockControl::RIGHT;  			break; -			 +  		case LLToolBarEnums::TOOLBAR_RIGHT:  			doc_at = LLDockControl::LEFT;  			break;  	} -	 +  	return doc_at;  } @@ -1996,7 +2401,7 @@ LLCallDialog(payload)  	if(instance && instance->getVisible())  	{  		instance->onCancel(instance); -	}	 +	}  }  void LLCallDialog::draw() @@ -2053,7 +2458,7 @@ bool LLCallDialog::lifetimeHasExpired()  	if (mLifetimeTimer.getStarted())  	{  		F32 elapsed_time = mLifetimeTimer.getElapsedTimeF32(); -		if (elapsed_time > mLifetime)  +		if (elapsed_time > mLifetime)  		{  			return true;  		} @@ -2095,7 +2500,7 @@ void LLOutgoingCallDialog::show(const LLSD& key)  	}  	else  	{ -		getChild<LLUICtrl>("leaving")->setTextArg("[CURRENT_CHAT]", getString("localchat"));		 +		getChild<LLUICtrl>("leaving")->setTextArg("[CURRENT_CHAT]", getString("localchat"));  	}  	if (!mPayload["disconnected_channel_name"].asString().empty()) @@ -2115,13 +2520,11 @@ void LLOutgoingCallDialog::show(const LLSD& key)  	std::string callee_name = mPayload["session_name"].asString(); -	LLUUID session_id = mPayload["session_id"].asUUID(); -  	if (callee_name == "anonymous") // obsolete? Likely was part of avaline support  	{  		callee_name = getString("anonymous");  	} -	 +  	LLSD callee_id = mPayload["other_user_id"];  	// Beautification:  Since you know who you called, just show display name  	std::string title = callee_name; @@ -2177,7 +2580,7 @@ void LLOutgoingCallDialog::show(const LLSD& key)  		{  			const std::string& nearby_str = mPayload["ended_by_agent"] ? NEARBY_P2P_BY_AGENT : NEARBY_P2P_BY_OTHER;  			getChild<LLTextBox>(nearby_str)->setVisible(true); -		}  +		}  		else  		{  			getChild<LLTextBox>("nearby")->setVisible(true); @@ -2211,7 +2614,7 @@ void LLOutgoingCallDialog::onCancel(void* user_data)  	LLUUID session_id = self->mPayload["session_id"].asUUID();  	gIMMgr->endCall(session_id); -	 +  	self->closeFloater();  } @@ -2296,7 +2699,7 @@ BOOL LLIncomingCallDialog::postBuild()          LL_INFOS("IMVIEW") << "IncomingCall: notify_box_type was not provided" << LL_ENDL;          return TRUE;      } -	 +  	// init notification's lifetime  	std::istringstream ss( getString("lifetime") );  	if (!(ss >> mLifetime)) @@ -2471,7 +2874,7 @@ void LLIncomingCallDialog::processCallResponse(S32 response, const LLSD &payload  			if (session_name.empty())  			{  				LL_WARNS() << "Received an empty session name from a server" << LL_ENDL; -				 +  				switch(type){  				case IM_SESSION_CONFERENCE_START:  				case IM_SESSION_GROUP_START: @@ -2489,18 +2892,18 @@ void LLIncomingCallDialog::processCallResponse(S32 response, const LLSD &payload  						if (LLAvatarNameCache::get(caller_id, &av_name))  						{  							correct_session_name = av_name.getCompleteName(); -							correct_session_name.append(ADHOC_NAME_SUFFIX);  +							correct_session_name.append(ADHOC_NAME_SUFFIX);  						}  					}  					LL_INFOS("IMVIEW") << "Corrected session name is " << correct_session_name << LL_ENDL;  					break; -				default:  +				default:  					LL_WARNS("IMVIEW") << "Received an empty session name from a server and failed to generate a new proper session name" << LL_ENDL;  					break;  				}  			} -			 -			LLUUID new_session_id = gIMMgr->addSession(correct_session_name, type, session_id, true); + +			gIMMgr->addSession(correct_session_name, type, session_id, true);  			std::string url = gAgent.getRegion()->getCapability(  				"ChatSessionRequest"); @@ -2511,7 +2914,7 @@ void LLIncomingCallDialog::processCallResponse(S32 response, const LLSD &payload                      boost::bind(&chatterBoxInvitationCoro, url,                      session_id, inv_type)); -				// send notification message to the corresponding chat  +				// send notification message to the corresponding chat  				if (payload["notify_box_type"].asString() == "VoiceInviteGroup" || payload["notify_box_type"].asString() == "VoiceInviteAdHoc")  				{  					LLStringUtil::format_map_t string_args; @@ -2546,7 +2949,7 @@ void LLIncomingCallDialog::processCallResponse(S32 response, const LLSD &payload  			data["session-id"] = session_id;              LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, data, -                "Invitation declined",  +                "Invitation declined",                  "Invitation decline failed.");  		}  	} @@ -2566,7 +2969,7 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response)  	EInstantMessage type = (EInstantMessage)payload["type"].asInteger();  	LLIMMgr::EInvitationType inv_type = (LLIMMgr::EInvitationType)payload["inv_type"].asInteger();  	S32 option = LLNotificationsUtil::getSelectedOption(notification, response); -	switch(option)  +	switch(option)  	{  	case 0: // accept  		{ @@ -2586,7 +2989,7 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response)  			}  			else  			{ -				LLUUID new_session_id = gIMMgr->addSession( +				gIMMgr->addSession(  					payload["session_name"].asString(),  					type,  					session_id, true); @@ -2610,7 +3013,7 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response)  		}  	}  	/* FALLTHROUGH */ -	 +  	case 1: // decline  	{  		if (type == IM_SESSION_P2P_INVITE) @@ -2626,8 +3029,8 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response)  			LLSD data;  			data["method"] = "decline invitation";  			data["session-id"] = session_id; -            LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, data,  -                "Invitation declined.",  +            LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, data, +                "Invitation declined.",                  "Invitation decline failed.");  		}  	} @@ -2636,7 +3039,7 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response)  	gIMMgr->clearPendingInvitation(session_id);  	break;  	} -	 +  	return false;  } @@ -2652,7 +3055,7 @@ LLIMMgr::LLIMMgr()  	LLIMModel::getInstance()->addNewMsgCallback(boost::bind(&LLFloaterIMSession::sRemoveTypingIndicator, _1));  } -// Add a message to a session.  +// Add a message to a session.  void LLIMMgr::addMessage(  	const LLUUID& session_id,  	const LLUUID& target_id, @@ -2664,7 +3067,8 @@ void LLIMMgr::addMessage(  	U32 parent_estate_id,  	const LLUUID& region_id,  	const LLVector3& position, -	bool is_region_msg) +    bool is_region_msg, +    U32 timestamp)      // May be zero  {  	LLUUID other_participant_id = target_id; @@ -2684,7 +3088,7 @@ void LLIMMgr::addMessage(  		name_is_setted = true;  	}  	bool skip_message = false; -	bool from_linden = LLMuteList::getInstance()->isLinden(from); +	bool from_linden = LLMuteList::isLinden(from);      if (gSavedPerAccountSettings.getBOOL("VoiceCallsFriendsOnly") && !from_linden)  	{  		// Evaluate if we need to skip this message when that setting is true (default is false) @@ -2751,6 +3155,14 @@ void LLIMMgr::addMessage(  				return;  			} +            // Fetch group chat history, enabled by default. +            if (gSavedPerAccountSettings.getBOOL("FetchGroupChatHistory")) +            { +                std::string chat_url = gAgent.getRegion()->getCapability("ChatSessionRequest"); +                LLCoros::instance().launch("chatterBoxHistoryCoro", +                    boost::bind(&chatterBoxHistoryCoro, chat_url, session_id, from, msg, timestamp)); +            } +  			//Play sound for new conversations  			if (!skip_message & !gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNewConversation") == TRUE))  			{ @@ -2766,7 +3178,7 @@ void LLIMMgr::addMessage(  	if (!LLMuteList::getInstance()->isMuted(other_participant_id, LLMute::flagTextChat) && !skip_message)  	{ -		LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, msg, true, is_region_msg); +		LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, msg, true, is_region_msg, timestamp);  	}  	// Open conversation floater if offline messages are present @@ -2781,7 +3193,7 @@ void LLIMMgr::addMessage(  void LLIMMgr::addSystemMessage(const LLUUID& session_id, const std::string& message_name, const LLSD& args)  {  	LLUIString message; -	 +  	// null session id means near me (chat history)  	if (session_id.isNull())  	{ @@ -2821,7 +3233,7 @@ void LLIMMgr::addSystemMessage(const LLUUID& session_id, const std::string& mess  S32 LLIMMgr::getNumberOfUnreadIM()  {  	std::map<LLUUID, LLIMModel::LLIMSession*>::iterator it; -	 +  	S32 num = 0;  	for(it = LLIMModel::getInstance()->mId2SessionMap.begin(); it != LLIMModel::getInstance()->mId2SessionMap.end(); ++it)  	{ @@ -2848,7 +3260,7 @@ void LLIMMgr::autoStartCallOnStartup(const LLUUID& session_id)  {  	LLIMModel::LLIMSession *session = LLIMModel::getInstance()->findIMSession(session_id);  	if (!session) return; -	 +  	if (session->mSessionInitialized)  	{  		startCall(session_id); @@ -2856,7 +3268,7 @@ void LLIMMgr::autoStartCallOnStartup(const LLUUID& session_id)  	else  	{  		session->mStartCallOnInitialize = true; -	}	 +	}  }  LLUUID LLIMMgr::addP2PSession(const std::string& name, @@ -2893,7 +3305,7 @@ LLUUID LLIMMgr::addSession(  	return session_id;  } -// Adds a session using the given session_id.  If the session already exists  +// Adds a session using the given session_id.  If the session already exists  // the dialog type is assumed correct. Returns the uuid of the session.  LLUUID LLIMMgr::addSession(  	const std::string& name, @@ -2956,9 +3368,9 @@ LLUUID LLIMMgr::addSession(  	//we don't need to show notes about online/offline, mute/unmute users' statuses for existing sessions  	if (!new_session) return session_id; -	 +      LL_INFOS("IMVIEW") << "LLIMMgr::addSession, new session added, name = " << name << ", session id = " << session_id << LL_ENDL; -     +  	//Per Plan's suggestion commented "explicit offline status warning" out to make Dessie happier (see EXT-3609)  	//*TODO After February 2010 remove this commented out line if no one will be missing that warning  	//noteOfflineUsers(session_id, floater, ids); @@ -2988,7 +3400,7 @@ bool LLIMMgr::leaveSession(const LLUUID& session_id)  void LLIMMgr::removeSession(const LLUUID& session_id)  {  	llassert_always(hasSession(session_id)); -	 +  	clearPendingInvitation(session_id);  	clearPendingAgentListUpdates(session_id); @@ -3000,9 +3412,9 @@ void LLIMMgr::removeSession(const LLUUID& session_id)  }  void LLIMMgr::inviteToSession( -	const LLUUID& session_id,  -	const std::string& session_name,  -	const LLUUID& caller_id,  +	const LLUUID& session_id, +	const std::string& session_name, +	const LLUUID& caller_id,  	const std::string& caller_name,  	EInstantMessage type,  	EInvitationType inv_type, @@ -3014,7 +3426,7 @@ void LLIMMgr::inviteToSession(  	std::string question_type = "VoiceInviteQuestionDefault";  	BOOL voice_invite = FALSE; -	bool is_linden = LLMuteList::getInstance()->isLinden(caller_name); +	bool is_linden = LLMuteList::isLinden(caller_name);  	if(type == IM_SESSION_P2P_INVITE) @@ -3119,22 +3531,22 @@ void LLIMMgr::inviteToSession(  	{  		if (caller_name.empty())  		{ -			LLAvatarNameCache::get(caller_id,  +			LLAvatarNameCache::get(caller_id,  				boost::bind(&LLIMMgr::onInviteNameLookup, payload, _1, _2));  		}  		else  		{  			LLFloaterReg::showInstance("incoming_call", payload, FALSE);  		} -		 -		// Add the caller to the Recent List here (at this point  + +		// Add the caller to the Recent List here (at this point  		// "incoming_call" floater is shown and the recipient can  		// reject the call), because even if a recipient will reject  		// the call, the caller should be added to the recent list  		// anyway. STORM-507.  		if(type == IM_SESSION_P2P_INVITE)  			LLRecentPeople::instance().add(caller_id); -		 +  		mPendingInvitations[session_id.asString()] = LLSD();  	}  } @@ -3331,7 +3743,7 @@ bool LLIMMgr::startCall(const LLUUID& session_id, LLVoiceChannel::EDirection dir  {  	LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(session_id);  	if (!voice_channel) return false; -	 +  	voice_channel->setCallDirection(direction);  	voice_channel->activate();  	return true; @@ -3449,7 +3861,7 @@ void LLIMMgr::noteMutedUsers(const LLUUID& session_id,  	if(count > 0)  	{  		LLIMModel* im_model = LLIMModel::getInstance(); -		 +  		for(S32 i = 0; i < count; ++i)  		{  			if( ml->isMuted(ids.at(i)) ) @@ -3527,7 +3939,15 @@ public:  				if ( body.has("session_info") )  				{  					im_floater->processSessionUpdate(body["session_info"]); -				} + +                    // Send request for chat history, if enabled. +                    if (gSavedPerAccountSettings.getBOOL("FetchGroupChatHistory")) +                    { +                        std::string url = gAgent.getRegion()->getCapability("ChatSessionRequest"); +                        LLCoros::instance().launch("chatterBoxHistoryCoro", +                            boost::bind(&chatterBoxHistoryCoro, url, session_id, "", "", 0)); +                    } +                }  			}  			gIMMgr->clearPendingAgentListUpdates(session_id); @@ -3656,7 +4076,7 @@ public:  			LLUUID session_id = message_params["id"].asUUID();  			std::vector<U8> bin_bucket = message_params["data"]["binary_bucket"].asBinary();  			U8 offline = (U8)message_params["offline"].asInteger(); -			 +  			time_t timestamp =  				(time_t) message_params["timestamp"].asInteger(); @@ -3693,7 +4113,9 @@ public:  				IM_SESSION_INVITE,  				message_params["parent_estate_id"].asInteger(),  				message_params["region_id"].asUUID(), -				ll_vector3_from_sd(message_params["position"])); +				ll_vector3_from_sd(message_params["position"]), +                false,      // is_region_message +                timestamp);  			if (LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat))  			{ @@ -3719,8 +4141,8 @@ public:  			}  			gIMMgr->inviteToSession( -				input["body"]["session_id"].asUUID(),  -				input["body"]["session_name"].asString(),  +				input["body"]["session_id"].asUUID(), +				input["body"]["session_name"].asString(),  				input["body"]["from_id"].asUUID(),  				input["body"]["from_name"].asString(),  				IM_SESSION_INVITE, @@ -3729,8 +4151,8 @@ public:  		else if ( input["body"].has("immediate") )  		{  			gIMMgr->inviteToSession( -				input["body"]["session_id"].asUUID(),  -				input["body"]["session_name"].asString(),  +				input["body"]["session_id"].asUUID(), +				input["body"]["session_name"].asString(),  				input["body"]["from_id"].asUUID(),  				input["body"]["from_name"].asString(),  				IM_SESSION_INVITE, diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index 326e8f22e3..946eb02f26 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -42,6 +42,7 @@ class LLAvatarName;  class LLFriendObserver;  class LLCallDialogManager;	  class LLIMSpeakerMgr; +  /**   * Timeout Timer for outgoing Ad-Hoc/Group IM sessions which being initialized by the server   */ @@ -63,11 +64,14 @@ private:  class LLIMModel :  public LLSingleton<LLIMModel>  {  	LLSINGLETON(LLIMModel); +  public: -	struct LLIMSession : public boost::signals2::trackable +    typedef std::list<LLSD> chat_message_list_t; + +    struct LLIMSession : public boost::signals2::trackable  	{ -		typedef enum e_session_type +        typedef enum e_session_type  		{   // for now we have 4 predefined types for a session  			P2P_SESSION,  			GROUP_SESSION, @@ -75,15 +79,23 @@ public:  			NONE_SESSION,  		} SType; -		LLIMSession(const LLUUID& session_id, const std::string& name,  +		LLIMSession(const LLUUID& session_id, const std::string& name,  			const EInstantMessage& type, const LLUUID& other_participant_id, const uuid_vec_t& ids, bool voice, bool has_offline_msg);  		virtual ~LLIMSession();  		void sessionInitReplyReceived(const LLUUID& new_session_id); -		void addMessagesFromHistory(const std::list<LLSD>& history); -		void addMessage(const std::string& from, const LLUUID& from_id, const std::string& utf8_text, const std::string& time, const bool is_history = false, bool is_region_msg = false); -		void onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction); -		 +		void addMessagesFromHistoryCache(const std::list<LLSD>& history);        // From local file +        void addMessagesFromServerHistory(const LLSD& history, const std::string& target_from, const std::string& target_message, U32 timestamp);  // From chat server +		void addMessage(const std::string& from, +                        const LLUUID& from_id, +                        const std::string& utf8_text, +                        const std::string& time, +                        const bool is_history, +                        const bool is_region_msg, +                        U32 timestamp); + +        void onVoiceChannelStateChanged(const LLVoiceChannel::EState& old_state, const LLVoiceChannel::EState& new_state, const LLVoiceChannel::EDirection& direction); +  		/** @deprecated */  		static void chatFromLogFile(LLLogChat::ELogLineType type, const LLSD& msg, void* userdata); @@ -112,6 +124,10 @@ public:  		uuid_vec_t mInitialTargetIDs;  		std::string mHistoryFileName; +        // Saved messages from the last minute of history read from the local group chat cache file +        std::string mLastHistoryCacheDateTime; +        chat_message_list_t mLastHistoryCacheMsgs; +  		// connection to voice channel state change signal  		boost::signals2::connection mVoiceChannelStateChangeConnection; @@ -121,7 +137,7 @@ public:  		// does include all incoming messages  		S32 mNumUnread; -		std::list<LLSD> mMsgs; +        chat_message_list_t mMsgs;  		LLVoiceChannel* mVoiceChannel;  		LLIMSpeakerMgr* mSpeakers; @@ -208,29 +224,43 @@ public:  	 * and also saved into a file if log2file is specified.  	 * It sends new message signal for each added message.  	 */ -	bool addMessage(const LLUUID& session_id, const std::string& from, const LLUUID& other_participant_id, const std::string& utf8_text, bool log2file = true, bool is_region_msg = false); +	void addMessage(const LLUUID& session_id, +                    const std::string& from, +                    const LLUUID& other_participant_id, +                    const std::string& utf8_text, +                    bool log2file = true, +                    bool is_region_msg = false, +                    U32 time_stamp = 0); + +    void processAddingMessage(const LLUUID& session_id, +                    const std::string& from, +                    const LLUUID& from_id, +                    const std::string& utf8_text, +                    bool log2file, +                    bool is_region_msg, +                    U32 time_stamp);  	/**  	 * Similar to addMessage(...) above but won't send a signal about a new message added  	 */ -	LLIMModel::LLIMSession* addMessageSilently(const LLUUID& session_id, const std::string& from, const LLUUID& from_id,  -		const std::string& utf8_text, bool log2file = true, bool is_region_msg = false); +	LLIMModel::LLIMSession* addMessageSilently(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, +		const std::string& utf8_text, bool log2file = true, bool is_region_msg = false, U32 timestamp = 0);  	/**  	 * Add a system message to an IM Model  	 */ -	bool proccessOnlineOfflineNotification(const LLUUID& session_id, const std::string& utf8_text); +	void proccessOnlineOfflineNotification(const LLUUID& session_id, const std::string& utf8_text);  	/** -	 * Get a session's name.  -	 * For a P2P chat - it's an avatar's name,  +	 * Get a session's name. +	 * For a P2P chat - it's an avatar's name,  	 * For a group chat - it's a group's name  	 * For an incoming ad-hoc chat - is received from the server and is in a from of "<Avatar's name> Conference"  	 *	It is updated in LLIMModel::LLIMSession's constructor to localize the "Conference".  	 */  	const std::string getName(const LLUUID& session_id) const; -	/**  +	/**  	 * Get number of unread messages in a session with session_id  	 * Returns -1 if the session with session_id doesn't exist  	 */ @@ -282,7 +312,7 @@ public:  	bool logToFile(const std::string& file_name, const std::string& from, const LLUUID& from_id, const std::string& utf8_text);  private: -	 +  	/**  	 * Populate supplied std::list with messages starting from index specified by start_index without  	 * emitting no unread messages signal. @@ -292,7 +322,7 @@ private:  	/**  	 * Add message to a list of message associated with session specified by session_id  	 */ -	bool addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text, bool is_region_msg = false); +	bool addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text, bool is_region_msg, U32 timestamp);  }; @@ -334,7 +364,8 @@ public:  					U32 parent_estate_id = 0,  					const LLUUID& region_id = LLUUID::null,  					const LLVector3& position = LLVector3::zero, -					bool is_region_msg = false); +                    bool is_region_msg = false, +                    U32 timestamp = 0);  	void addSystemMessage(const LLUUID& session_id, const std::string& message_name, const LLSD& args); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 7793b71f56..db347f7096 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -831,6 +831,12 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id,  			{  				disabled_items.push_back(std::string("Find Original"));  			} + +            items.push_back(std::string("Cut")); +            if (!isItemMovable() || !isItemRemovable()) +            { +                disabled_items.push_back(std::string("Cut")); +            }  		}  		else  		{ @@ -2140,6 +2146,7 @@ bool LLItemBridge::isItemCopyable(bool can_copy_as_link) const      static LLCachedControl<bool> inventory_linking(gSavedSettings, "InventoryLinking", true);      return (can_copy_as_link && inventory_linking) +        || (mIsLink && inventory_linking)          || item->getPermissions().allowCopyBy(gAgent.getID());  } @@ -2346,6 +2353,12 @@ BOOL LLFolderBridge::isUpToDate() const  bool LLFolderBridge::isItemCopyable(bool can_copy_as_link) const  { +    if (can_copy_as_link && !LLFolderType::lookupIsProtectedType(getPreferredType())) +    { +        // Can copy and paste unprotected folders as links +        return true; +    } +  	// Folders are copyable if items in them are, recursively, copyable.  	// Get the content of the folder diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index 707ff2b7b6..e3a6b2dc85 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -437,7 +437,6 @@ bool LLInventoryFilter::checkAgainstFilterType(const LLFolderViewModelItemInvent  bool LLInventoryFilter::checkAgainstFilterType(const LLInventoryItem* item) const  {  	LLInventoryType::EType object_type = item->getInventoryType(); -	const LLUUID object_id = item->getUUID();  	const U32 filterTypes = mFilterOps.mFilterTypes; diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 5755bc692e..67240ac7e7 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -529,7 +529,11 @@ BOOL get_is_item_worn(const LLUUID& id)  	const LLViewerInventoryItem* item = gInventory.getItem(id);  	if (!item)  		return FALSE; - +     +    if (item->getIsLinkType() && !gInventory.getItem(item->getLinkedUUID())) +    { +        return FALSE; +    }  	// Consider the item as worn if it has links in COF.  	if (LLAppearanceMgr::instance().isLinkedInCOF(id))  	{ @@ -787,7 +791,7 @@ void show_item_original(const LLUUID& item_uuid)          LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();          if (main_inventory)          { -            main_inventory->resetFilters(); +            main_inventory->resetAllItemsFilters();          }          reset_inventory_filter(); @@ -795,6 +799,7 @@ void show_item_original(const LLUUID& item_uuid)          {              LLFloaterReg::toggleInstanceOrBringToFront("inventory");          } +        sidepanel_inventory->showInventoryPanel();          const LLUUID inbox_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX);          if (gInventory.isObjectDescendentOf(gInventory.getLinkedItemID(item_uuid), inbox_id)) @@ -1406,9 +1411,6 @@ bool move_item_to_marketplacelistings(LLInventoryItem* inv_item, LLUUID dest_fol                  LLNotificationsUtil::add("MerchantPasteFailed", subs);                  return false;              } -             -            // Get the parent folder of the moved item : we may have to update it -            LLUUID src_folder = viewer_inv_item->getParentUUID();              if (copy)              { @@ -2653,7 +2655,12 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root      }      else      { -        std::copy(selected_uuid_set.begin(), selected_uuid_set.end(), std::back_inserter(ids)); +        for (std::set<LLFolderViewItem*>::iterator it = selected_items.begin(), end_it = selected_items.end(); +            it != end_it; +            ++it) +        { +            ids.push_back(static_cast<LLFolderViewModelItemInventory*>((*it)->getViewModelItem())->getUUID()); +        }      }      // Check for actions that get handled in bulk @@ -2714,7 +2721,7 @@ void LLInventoryAction::doToSelected(LLInventoryModel* model, LLFolderView* root      }      else if ("ungroup_folder_items" == action)      { -        if (selected_uuid_set.size() == 1) +        if (ids.size() == 1)          {              LLInventoryCategory* inv_cat = gInventory.getCategory(*ids.begin());              if (!inv_cat || LLFolderType::lookupIsProtectedType(inv_cat->getPreferredType())) diff --git a/indra/newview/llinventorylistitem.h b/indra/newview/llinventorylistitem.h index d4dd212cc3..cf713a6930 100644 --- a/indra/newview/llinventorylistitem.h +++ b/indra/newview/llinventorylistitem.h @@ -197,6 +197,7 @@ protected:  	virtual BOOL handleToolTip( S32 x, S32 y, MASK mask);  	const LLUUID mInventoryItemUUID; +    bool mHovered;  private: @@ -221,7 +222,6 @@ private:  	LLUIImagePtr	mSelectedImage;  	LLUIImagePtr	mSeparatorImage; -	bool			mHovered;  	bool			mSelected;  	bool			mSeparatorVisible; diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index c7491bd788..0bbf201dc6 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1636,6 +1636,9 @@ void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links, boo  		LL_WARNS(LOG_INV) << "Deleting non-existent object [ id: " << id << " ] " << LL_ENDL;  		return;  	} + +    //collect the links before removing the item from mItemMap +    LLInventoryModel::item_array_t links = collectLinksTo(id);  	LL_DEBUGS(LOG_INV) << "Deleting inventory object " << id << LL_ENDL;  	mLastItem = NULL; @@ -1691,37 +1694,36 @@ void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links, boo  	// Can't have links to links, so there's no need for this update  	// if the item removed is a link. Can also skip if source of the  	// update is getting broken link info separately. -	obj = NULL; // delete obj  	if (fix_broken_links && !is_link_type)  	{ -		updateLinkedObjectsFromPurge(id); +        rebuildLinkItems(links);  	} +	obj = nullptr; // delete obj  	if (do_notify_observers)  	{  		notifyObservers();  	}  } -void LLInventoryModel::updateLinkedObjectsFromPurge(const LLUUID &baseobj_id) +void LLInventoryModel::rebuildLinkItems(LLInventoryModel::item_array_t& items)  { -	LLInventoryModel::item_array_t item_array = collectLinksTo(baseobj_id); - -	// REBUILD is expensive, so clear the current change list first else -	// everything else on the changelist will also get rebuilt. -	if (item_array.size() > 0) -	{ -		notifyObservers(); -		for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); -			iter != item_array.end(); -			iter++) -		{ -			const LLViewerInventoryItem *linked_item = (*iter); -			const LLUUID &item_id = linked_item->getUUID(); -			if (item_id == baseobj_id) continue; -			addChangedMask(LLInventoryObserver::REBUILD, item_id); -		} -		notifyObservers(); -	} +    // REBUILD is expensive, so clear the current change list first else +    // everything else on the changelist will also get rebuilt. +    if (items.size() > 0) +    { +        notifyObservers(); +        for (LLInventoryModel::item_array_t::const_iterator iter = items.begin(); +            iter != items.end(); +            iter++) +        { +            const LLViewerInventoryItem *linked_item = (*iter); +            if (linked_item) +            { +                addChangedMask(LLInventoryObserver::REBUILD, linked_item->getUUID()); +            } +        } +        notifyObservers(); +    }  }  // Add/remove an observer. If the observer is destroyed, be sure to @@ -1951,18 +1953,20 @@ void LLInventoryModel::cache(  		items,  		INCLUDE_TRASH,  		can_cache); -	std::string inventory_filename = getInvCacheAddres(agent_id); -	saveToFile(inventory_filename, categories, items); -	std::string gzip_filename(inventory_filename); +    // Use temporary file to avoid potential conflicts with other +    // instances (even a 'read only' instance unzips into a file) +    std::string temp_file = gDirUtilp->getTempFilename(); +	saveToFile(temp_file, categories, items); +    std::string gzip_filename = getInvCacheAddres(agent_id);  	gzip_filename.append(".gz"); -	if(gzip_file(inventory_filename, gzip_filename)) +	if(gzip_file(temp_file, gzip_filename))  	{ -		LL_DEBUGS(LOG_INV) << "Successfully compressed " << inventory_filename << LL_ENDL; -		LLFile::remove(inventory_filename); +		LL_DEBUGS(LOG_INV) << "Successfully compressed " << temp_file << " to " << gzip_filename << LL_ENDL; +		LLFile::remove(temp_file);  	}  	else  	{ -		LL_WARNS(LOG_INV) << "Unable to compress " << inventory_filename << LL_ENDL; +		LL_WARNS(LOG_INV) << "Unable to compress " << temp_file << " into " << gzip_filename << LL_ENDL;  	}  } @@ -2715,7 +2719,6 @@ void LLInventoryModel::buildParentChildMap()  			// some accounts has pbroken inventory root folders  			std::string name = "My Inventory"; -			LLUUID prev_root_id = mRootFolderID;  			for (parent_cat_map_t::const_iterator it = mParentChildCategoryTree.begin(),  					 it_end = mParentChildCategoryTree.end(); it != it_end; ++it)  			{ @@ -3036,6 +3039,7 @@ bool LLInventoryModel::saveToFile(const std::string& filename,                  return false;              }          } +        fileXML.flush();          fileXML.close(); diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index c4133ff9bb..685c2c0fe5 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -445,7 +445,7 @@ public:  	void checkTrashOverflow();  protected: -	void updateLinkedObjectsFromPurge(const LLUUID& baseobj_id); +    void rebuildLinkItems(LLInventoryModel::item_array_t& items);  	//--------------------------------------------------------------------  	// Reorder diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 406c8b89d0..4a9b471a47 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -363,7 +363,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch()  	//If there are items in mFetchQueue, we want to check the time since the last bulkFetch was   	//sent.  If it exceeds our retry time, go ahead and fire off another batch.    	LLViewerRegion * region(gAgent.getRegion()); -	if (! region || gDisconnected) +	if (! region || gDisconnected || LLApp::isExiting())  	{  		return;  	} diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 6b102c7500..8029486d6f 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -211,7 +211,11 @@ LLFolderView * LLInventoryPanel::createFolderRoot(LLUUID root_id )      p.allow_drop = mParams.allow_drop_on_root;      p.options_menu = "menu_inventory.xml"; -    return LLUICtrlFactory::create<LLFolderView>(p); +	LLFolderView* fv = LLUICtrlFactory::create<LLFolderView>(p); +	fv->setCallbackRegistrar(&mCommitCallbackRegistrar); +	fv->setEnableRegistrar(&mEnableCallbackRegistrar); + +	return fv;  }  void LLInventoryPanel::clearFolderRoot() @@ -264,6 +268,7 @@ void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params)  	}  	mCommitCallbackRegistrar.popScope();  	mFolderRoot.get()->setCallbackRegistrar(&mCommitCallbackRegistrar); +	mFolderRoot.get()->setEnableRegistrar(&mEnableCallbackRegistrar);  	// Scroller  		LLRect scroller_view_rect = getRect(); @@ -1622,6 +1627,7 @@ void LLInventoryPanel::purgeSelectedItems()      if (inventory_selected.empty()) return;      LLSD args;      S32 count = inventory_selected.size(); +    std::vector<LLUUID> selected_items;      for (std::set<LLFolderViewItem*>::const_iterator it = inventory_selected.begin(), end_it = inventory_selected.end();          it != end_it;          ++it) @@ -1631,27 +1637,23 @@ void LLInventoryPanel::purgeSelectedItems()          LLInventoryModel::item_array_t items;          gInventory.collectDescendents(item_id, cats, items, LLInventoryModel::INCLUDE_TRASH);          count += items.size() + cats.size(); +        selected_items.push_back(item_id);      }      args["COUNT"] = count; -    LLNotificationsUtil::add("PurgeSelectedItems", args, LLSD(), boost::bind(&LLInventoryPanel::callbackPurgeSelectedItems, this, _1, _2)); +    LLNotificationsUtil::add("PurgeSelectedItems", args, LLSD(), boost::bind(callbackPurgeSelectedItems, _1, _2, selected_items));  } -void LLInventoryPanel::callbackPurgeSelectedItems(const LLSD& notification, const LLSD& response) +// static +void LLInventoryPanel::callbackPurgeSelectedItems(const LLSD& notification, const LLSD& response, const std::vector<LLUUID> inventory_selected)  { -    if (!mFolderRoot.get()) return; -      S32 option = LLNotificationsUtil::getSelectedOption(notification, response);      if (option == 0)      { -        const std::set<LLFolderViewItem*> inventory_selected = mFolderRoot.get()->getSelectionList();          if (inventory_selected.empty()) return; -        std::set<LLFolderViewItem*>::const_iterator it = inventory_selected.begin(); -        const std::set<LLFolderViewItem*>::const_iterator it_end = inventory_selected.end(); -        for (; it != it_end; ++it) +        for (auto it : inventory_selected)          { -            LLUUID item_id = static_cast<LLFolderViewModelItemInventory*>((*it)->getViewModelItem())->getUUID(); -            remove_inventory_object(item_id, NULL); +            remove_inventory_object(it, NULL);          }      }  } diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index 552c61b915..2c782a5ea7 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -260,7 +260,7 @@ public:      // Clean up stuff when the folder root gets deleted      void clearFolderRoot(); -    void callbackPurgeSelectedItems(const LLSD& notification, const LLSD& response); +    static void callbackPurgeSelectedItems(const LLSD& notification, const LLSD& response, const std::vector<LLUUID> inventory_selected);  protected:  	void openStartFolderOrMyInventory(); // open the first level of inventory diff --git a/indra/newview/llkeyconflict.cpp b/indra/newview/llkeyconflict.cpp index d3ba18525b..60f8aca94c 100644 --- a/indra/newview/llkeyconflict.cpp +++ b/indra/newview/llkeyconflict.cpp @@ -171,8 +171,9 @@ bool LLKeyConflictHandler::isReservedByMenu(const KEY &key, const MASK &mask)      {          return false;      } -    return (gMenuBarView && gMenuBarView->hasAccelerator(key, mask)) -           || (gLoginMenuBarView && gLoginMenuBarView->hasAccelerator(key, mask)); +    // At the moment controls are only applicable inworld, +    // ignore gLoginMenuBarView +    return gMenuBarView && gMenuBarView->hasAccelerator(key, mask);  }  // static @@ -182,8 +183,7 @@ bool LLKeyConflictHandler::isReservedByMenu(const LLKeyData &data)      {          return false;      } -    return (gMenuBarView && gMenuBarView->hasAccelerator(data.mKey, data.mMask)) -           || (gLoginMenuBarView && gLoginMenuBarView->hasAccelerator(data.mKey, data.mMask)); +    return gMenuBarView && gMenuBarView->hasAccelerator(data.mKey, data.mMask);  }  bool LLKeyConflictHandler::registerControl(const std::string &control_name, U32 index, EMouseClickType mouse, KEY key, MASK mask, bool ignore_mask) diff --git a/indra/newview/lllistcontextmenu.cpp b/indra/newview/lllistcontextmenu.cpp index 6bda8b1d0d..77185411c5 100644 --- a/indra/newview/lllistcontextmenu.cpp +++ b/indra/newview/lllistcontextmenu.cpp @@ -51,6 +51,7 @@ LLListContextMenu::~LLListContextMenu()  	if (!mMenuHandle.isDead())  	{  		mMenuHandle.get()->die(); +		mMenuHandle.markDead();  	}  } @@ -59,13 +60,8 @@ void LLListContextMenu::show(LLView* spawning_view, const uuid_vec_t& uuids, S32  	LLContextMenu* menup = mMenuHandle.get();  	if (menup)  	{ -		//preventing parent (menu holder) from deleting already "dead" context menus on exit -		LLView* parent = menup->getParent(); -		if (parent) -		{ -			parent->removeChild(menup); -		} -		delete menup; +		menup->die(); +		mMenuHandle.markDead();  		mUUIDs.clear();  	} diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index fb9885b454..ba82ff0b0f 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -62,6 +62,7 @@  const S32 LOG_RECALL_SIZE = 2048;  const std::string LL_IM_TIME("time"); +const std::string LL_IM_DATE_TIME("datetime");  const std::string LL_IM_TEXT("message");  const std::string LL_IM_FROM("from");  const std::string LL_IM_FROM_ID("from_id"); @@ -133,14 +134,14 @@ void append_to_last_message(std::list<LLSD>& messages, const std::string& line)  	messages.back()[LL_IM_TEXT] = im_text;  } -std::string remove_utf8_bom(const char* buf) +const char* remove_utf8_bom(const char* buf)  { -	std::string res(buf); -	if (res[0] == (char)0xEF && res[1] == (char)0xBB && res[2] == (char)0xBF) -	{ -		res.erase(0, 3); +    const char* start = buf; +	if (start[0] == (char)0xEF && start[1] == (char)0xBB && start[2] == (char)0xBF) +	{   // If string starts with the magic bytes, return pointer after it. +        start += 3;  	} -	return res; +	return start;  }  class LLLogChatTimeScanner: public LLSingleton<LLLogChatTimeScanner> @@ -315,7 +316,7 @@ std::string LLLogChat::cleanFileName(std::string filename)  	return filename;  } -std::string LLLogChat::timestamp(bool withdate) +std::string LLLogChat::timestamp2LogString(U32 timestamp, bool withdate)  {  	std::string timeStr;  	if (withdate) @@ -333,7 +334,14 @@ std::string LLLogChat::timestamp(bool withdate)  	}  	LLSD substitution; -	substitution["datetime"] = (S32)time_corrected(); +    if (timestamp == 0) +    { +        substitution["datetime"] = (S32)time_corrected(); +    } +    else +    {   // timestamp is correct utc already +        substitution["datetime"] = (S32)timestamp; +    }  	LLStringUtil::format (timeStr, substitution);  	return timeStr; @@ -355,7 +363,7 @@ void LLLogChat::saveHistory(const std::string& filename,  		llassert(tmp_filename.size());  		return;  	} -	 +  	llofstream file(LLLogChat::makeLogFileName(filename).c_str(), std::ios_base::app);  	if (!file.is_open())  	{ @@ -366,7 +374,7 @@ void LLLogChat::saveHistory(const std::string& filename,  	LLSD item;  	if (gSavedPerAccountSettings.getBOOL("LogTimestamp")) -		 item["time"] = LLLogChat::timestamp(gSavedPerAccountSettings.getBOOL("LogTimestampDate")); +		 item["time"] = LLLogChat::timestamp2LogString(0, gSavedPerAccountSettings.getBOOL("LogTimestampDate"));  	item["from_id"]	= from_id;  	item["message"]	= line; @@ -374,7 +382,7 @@ void LLLogChat::saveHistory(const std::string& filename,  	//adding "Second Life:" for all system messages to make chat log history parsing more reliable  	if (from.empty() && from_id.isNull())  	{ -		item["from"] = SYSTEM_FROM;  +		item["from"] = SYSTEM_FROM;  	}  	else  	{ @@ -393,37 +401,60 @@ void LLLogChat::loadChatHistory(const std::string& file_name, std::list<LLSD>& m  {  	if (file_name.empty())  	{ -		LL_WARNS("LLLogChat::loadChatHistory") << "Session name is Empty!" << LL_ENDL; +		LL_WARNS("LLLogChat::loadChatHistory") << "Local history file name is empty!" << LL_ENDL;  		return ;  	}  	bool load_all_history = load_params.has("load_all_history") ? load_params["load_all_history"].asBoolean() : false; -	LLFILE* fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "r");/*Flawfinder: ignore*/ +    // Stat the file to find it and get the last history entry time +    llstat stat_data; + +    std::string log_file_name = LLLogChat::makeLogFileName(file_name); +    LL_DEBUGS("ChatHistory") << "First attempt to stat chat history file " << log_file_name << LL_ENDL; + +    S32 no_stat = LLFile::stat(log_file_name, &stat_data); + +    if (no_stat) +    { +        if (is_group) +        { +            std::string old_name(file_name); +            old_name.erase(old_name.size() - GROUP_CHAT_SUFFIX.size());     // trim off " (group)" +            log_file_name = LLLogChat::makeLogFileName(old_name); +            LL_DEBUGS("ChatHistory") << "Attempting to stat adjusted chat history file " << log_file_name << LL_ENDL; +            no_stat = LLFile::stat(log_file_name, &stat_data); +            if (!no_stat) +            {   // Found it without "(group)", copy to new naming style.  We already have the mod time in stat_data +                log_file_name = LLLogChat::makeLogFileName(file_name); +                LL_DEBUGS("ChatHistory") << "Attempt to stat copied history file " << log_file_name << LL_ENDL; +                LLFile::copy(LLLogChat::makeLogFileName(old_name), log_file_name); +            } +        } +        if (no_stat) +        { +            log_file_name = LLLogChat::oldLogFileName(file_name); +            LL_DEBUGS("ChatHistory") << "Attempt to stat old history file name " << log_file_name << LL_ENDL; +            no_stat = LLFile::stat(log_file_name, &stat_data); +            if (no_stat) +            { +                LL_DEBUGS("ChatHistory") << "No previous conversation log file found for " << file_name << LL_ENDL; +                return;						//No previous conversation with this name. +            } +        } +    } + +    // If we got here, we managed to stat the file. +    // Open the file to read +    LLFILE* fptr = LLFile::fopen(log_file_name, "r");       /*Flawfinder: ignore*/  	if (!fptr) -	{ -		if (is_group) -		{ -			std::string old_name(file_name); -			old_name.erase(old_name.size() - GROUP_CHAT_SUFFIX.size()); -			fptr = LLFile::fopen(LLLogChat::makeLogFileName(old_name), "r"); -			if (fptr) -			{ -				fclose(fptr); -				LLFile::copy(LLLogChat::makeLogFileName(old_name), LLLogChat::makeLogFileName(file_name)); -			} -			fptr = LLFile::fopen(LLLogChat::makeLogFileName(file_name), "r"); -		} -		if (!fptr) -		{ -			fptr = LLFile::fopen(LLLogChat::oldLogFileName(file_name), "r");/*Flawfinder: ignore*/ -			if (!fptr) -			{ -				return;						//No previous conversation with this name. -			} -		} +	{   // Ok, this is strange but not really tragic in the big picture of things +        LL_WARNS("ChatHistory") << "Unable to read file " << log_file_name << " after stat was successful" << LL_ENDL; +        return;  	} +    S32 save_num_messages = messages.size(); +  	char buffer[LOG_RECALL_SIZE];		/*Flawfinder: ignore*/  	char *bptr;  	S32 len; @@ -441,6 +472,7 @@ void LLLogChat::loadChatHistory(const std::string& file_name, std::list<LLSD>& m  	while (fgets(buffer, LOG_RECALL_SIZE, fptr)  && !feof(fptr))  	{  		len = strlen(buffer) - 1;		/*Flawfinder: ignore*/ +        // backfill any end of line characters with nulls  		for (bptr = (buffer + len); (*bptr == '\n' || *bptr == '\r') && bptr>buffer; bptr--)	*bptr='\0';  		if (firstline) @@ -473,6 +505,10 @@ void LLLogChat::loadChatHistory(const std::string& file_name, std::list<LLSD>& m  		}  	}  	fclose(fptr); + +    LL_DEBUGS("ChatHistory") << "Read " << (messages.size() - save_num_messages) +        << " messages of chat history from " << log_file_name +        << " file mod time " << (F64)stat_data.st_mtime << LL_ENDL;  }  bool LLLogChat::historyThreadsFinished(LLUUID session_id) @@ -837,7 +873,8 @@ bool LLLogChat::isTranscriptFileFound(std::string fullname)  		{  			//matching a timestamp  			boost::match_results<std::string::const_iterator> matches; -			if (ll_regex_match(remove_utf8_bom(buffer), matches, TIMESTAMP)) +            std::string line(remove_utf8_bom(buffer)); +			if (ll_regex_match(line, matches, TIMESTAMP))  			{  				result = true;  			} @@ -847,7 +884,7 @@ bool LLLogChat::isTranscriptFileFound(std::string fullname)  	return result;  } -//*TODO mark object's names in a special way so that they will be distinguishable form avatar name  +//*TODO mark object's names in a special way so that they will be distinguishable form avatar name  //which are more strict by its nature (only firstname and secondname)  //Example, an object's name can be written like "Object <actual_object's_name>"  void LLChatLogFormatter::format(const LLSD& im, std::ostream& ostr) const @@ -865,7 +902,7 @@ void LLChatLogFormatter::format(const LLSD& im, std::ostream& ostr) const  		ostr << '[' << timestamp << ']' << TWO_SPACES;  	} -	//*TODO mark object's names in a special way so that they will be distinguishable form avatar name  +	//*TODO mark object's names in a special way so that they will be distinguishable from avatar name   	//which are more strict by its nature (only firstname and secondname)  	//Example, an object's name can be written like "Object <actual_object's_name>"  	if (im[LL_IM_FROM].isDefined()) @@ -928,7 +965,9 @@ bool LLChatLogParser::parse(std::string& raw, LLSD& im, const LLSD& parse_params  		timestamp.erase(0, 1);  		timestamp.erase(timestamp.length()-1, 1); -		if (cut_off_todays_date) +        im[LL_IM_DATE_TIME] = timestamp;    // Retain full date-time for merging chat histories + +        if (cut_off_todays_date)  		{  			LLLogChatTimeScanner::instance().checkAndCutOffDate(timestamp);  		} @@ -936,9 +975,9 @@ bool LLChatLogParser::parse(std::string& raw, LLSD& im, const LLSD& parse_params  		im[LL_IM_TIME] = timestamp;  	}  	else -	{ -		//timestamp is optional -		im[LL_IM_TIME] = ""; +	{   //timestamp is optional +        im[LL_IM_DATE_TIME] = ""; +        im[LL_IM_TIME] = "";  	}  	bool has_stuff = matches[IDX_STUFF].matched; diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h index c4b61ee716..5dce8ab1d2 100644 --- a/indra/newview/lllogchat.h +++ b/indra/newview/lllogchat.h @@ -92,7 +92,7 @@ public:  		LOG_END  	}; -	static std::string timestamp(bool withdate = false); +	static std::string timestamp2LogString(U32 timestamp, bool withdate);  	static std::string makeLogFileName(std::string(filename));  	static void renameLogFile(const std::string& old_filename, const std::string& new_filename);  	/** @@ -201,6 +201,7 @@ extern const std::string GROUP_CHAT_SUFFIX;  // LLSD map lookup constants  extern const std::string LL_IM_TIME; //("time"); +extern const std::string LL_IM_DATE_TIME; //("datetime");  extern const std::string LL_IM_TEXT; //("message");  extern const std::string LL_IM_FROM; //("from");  extern const std::string LL_IM_FROM_ID; //("from_id"); diff --git a/indra/newview/llmaterialmgr.cpp b/indra/newview/llmaterialmgr.cpp index 11aa607393..a52f7244f3 100644 --- a/indra/newview/llmaterialmgr.cpp +++ b/indra/newview/llmaterialmgr.cpp @@ -429,12 +429,10 @@ void LLMaterialMgr::onGetResponse(bool success, const LLSD& content, const LLUUI  	llassert(content.has(MATERIALS_CAP_ZIP_FIELD));  	llassert(content[MATERIALS_CAP_ZIP_FIELD].isBinary()); -	LLSD::Binary content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary(); -	std::string content_string(reinterpret_cast<const char*>(content_binary.data()), content_binary.size()); -	std::istringstream content_stream(content_string); +	const LLSD::Binary& content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary();  	LLSD response_data; -	U32 uzip_result = LLUZipHelper::unzip_llsd(response_data, content_stream, content_binary.size()); +	U32 uzip_result = LLUZipHelper::unzip_llsd(response_data, content_binary.data(), content_binary.size());  	if (uzip_result != LLUZipHelper::ZR_OK)  	{  		LL_WARNS("Materials") << "Cannot unzip LLSD binary content: " << uzip_result << LL_ENDL; @@ -472,12 +470,10 @@ void LLMaterialMgr::onGetAllResponse(bool success, const LLSD& content, const LL  	llassert(content.has(MATERIALS_CAP_ZIP_FIELD));  	llassert(content[MATERIALS_CAP_ZIP_FIELD].isBinary()); -	LLSD::Binary content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary(); -	std::string content_string(reinterpret_cast<const char*>(content_binary.data()), content_binary.size()); -	std::istringstream content_stream(content_string); +	const LLSD::Binary& content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary();  	LLSD response_data; -	U32 uzip_result = LLUZipHelper::unzip_llsd(response_data, content_stream, content_binary.size()); +	U32 uzip_result = LLUZipHelper::unzip_llsd(response_data, content_binary.data(), content_binary.size());  	if (uzip_result != LLUZipHelper::ZR_OK)  	{  		LL_WARNS("Materials") << "Cannot unzip LLSD binary content: " << uzip_result << LL_ENDL; @@ -541,12 +537,10 @@ void LLMaterialMgr::onPutResponse(bool success, const LLSD& content)  	llassert(content.has(MATERIALS_CAP_ZIP_FIELD));  	llassert(content[MATERIALS_CAP_ZIP_FIELD].isBinary()); -	LLSD::Binary content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary(); -	std::string content_string(reinterpret_cast<const char*>(content_binary.data()), content_binary.size()); -	std::istringstream content_stream(content_string); +	const LLSD::Binary& content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary();  	LLSD response_data; -	U32 uzip_result = LLUZipHelper::unzip_llsd(response_data, content_stream, content_binary.size()); +	U32 uzip_result = LLUZipHelper::unzip_llsd(response_data, content_binary.data(), content_binary.size());  	if (uzip_result != LLUZipHelper::ZR_OK)  	{  		LL_WARNS("Materials") << "Cannot unzip LLSD binary content: " << uzip_result << LL_ENDL; @@ -666,8 +660,8 @@ void LLMaterialMgr::processGetQueue()  		{  			material_queue_t::iterator itMaterial = loopMaterial++;  			materialsData.append((*itMaterial).asLLSD()); -			materials.erase(itMaterial);  			markGetPending(region_id, *itMaterial); +			materials.erase(itMaterial);  		}  		if (materials.empty())  		{ diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index 9142aadab9..36ac1bdf97 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -106,7 +106,6 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :  	mTrusted(p.trusted_content),  	mWindowShade(NULL),  	mHoverTextChanged(false), -	mContextMenu(NULL),      mAllowFileDownload(false)  {  	{ @@ -151,6 +150,13 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) :  LLMediaCtrl::~LLMediaCtrl()  { +	auto menu = mContextMenuHandle.get(); +	if (menu) +	{ +		menu->die(); +		mContextMenuHandle.markDead(); +	} +  	if (mMediaSource)  	{  		mMediaSource->remObserver( this ); @@ -336,15 +342,33 @@ BOOL LLMediaCtrl::handleRightMouseDown( S32 x, S32 y, MASK mask )  		setFocus( TRUE );  	} -	if (mContextMenu) +	auto menu = mContextMenuHandle.get(); +	if (!menu) +	{ +		LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registar; +		registar.add("Open.WebInspector", boost::bind(&LLMediaCtrl::onOpenWebInspector, this)); + +		// stinson 05/05/2014 : use this as the parent of the context menu if the static menu +		// container has yet to be created +		LLPanel* menuParent = (LLMenuGL::sMenuContainer != NULL) ? dynamic_cast<LLPanel*>(LLMenuGL::sMenuContainer) : dynamic_cast<LLPanel*>(this); +		llassert(menuParent != NULL); +		menu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>( +			"menu_media_ctrl.xml", menuParent, LLViewerMenuHolderGL::child_registry_t::instance()); +		if (menu) +		{ +			mContextMenuHandle = menu->getHandle(); +		} +	} + +	if (menu)  	{  		// hide/show debugging options  		bool media_plugin_debugging_enabled = gSavedSettings.getBOOL("MediaPluginDebugging"); -		mContextMenu->setItemVisible("open_webinspector", media_plugin_debugging_enabled ); -		mContextMenu->setItemVisible("debug_separator", media_plugin_debugging_enabled ); +		menu->setItemVisible("open_webinspector", media_plugin_debugging_enabled ); +		menu->setItemVisible("debug_separator", media_plugin_debugging_enabled ); -		mContextMenu->show(x, y); -		LLMenuGL::showPopup(this, mContextMenu, x, y); +		menu->show(x, y); +		LLMenuGL::showPopup(this, menu, x, y);  	}  	return TRUE; @@ -409,15 +433,6 @@ void LLMediaCtrl::onFocusLost()  //  BOOL LLMediaCtrl::postBuild ()  { -	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registar; -	registar.add("Open.WebInspector", boost::bind(&LLMediaCtrl::onOpenWebInspector, this)); - -	// stinson 05/05/2014 : use this as the parent of the context menu if the static menu -	// container has yet to be created -	LLPanel* menuParent = (LLMenuGL::sMenuContainer != NULL) ? dynamic_cast<LLPanel*>(LLMenuGL::sMenuContainer) : dynamic_cast<LLPanel*>(this); -	llassert(menuParent != NULL); -	mContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>( -		"menu_media_ctrl.xml", menuParent, LLViewerMenuHolderGL::child_registry_t::instance());  	setVisibleCallback(boost::bind(&LLMediaCtrl::onVisibilityChanged, this, _2));  	return TRUE; @@ -1230,11 +1245,6 @@ void LLMediaCtrl::setTrustedContent(bool trusted)  	}  } -void LLMediaCtrl::updateContextMenuParent(LLView* pNewParent) -{ -	mContextMenu->updateParent(pNewParent); -} -  bool LLMediaCtrl::wantsKeyUpKeyDown() const  {      return true; diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index bc4cbaae68..487c654adc 100644 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -174,8 +174,6 @@ public:  		LLUUID getTextureID() {return mMediaTextureID;} -		void updateContextMenuParent(LLView* pNewParent); -          // The Browser windows want keyup and keydown events. Overridden from LLFocusableElement to return true.          virtual bool    wantsKeyUpKeyDown() const;          virtual bool    wantsReturnKey() const; @@ -220,7 +218,7 @@ public:  			mTextureHeight;  		class LLWindowShade* mWindowShade; -		LLContextMenu* mContextMenu; +		LLHandle<LLContextMenu> mContextMenuHandle;  };  #endif // LL_LLMediaCtrl_H diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index a15a61429b..f937754368 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -77,6 +77,8 @@  #include "lluploaddialog.h"  #include "llfloaterreg.h" +#include "boost/iostreams/device/array.hpp" +#include "boost/iostreams/stream.hpp"  #include "boost/lexical_cast.hpp"  #ifndef LL_WINDOWS @@ -138,7 +140,7 @@  //                               data copied  //                               headerReceived() invoked  //                                 LLSD parsed -//                                 mMeshHeader, mMeshHeaderSize updated +//                                 mMeshHeader updated  //                                 scan mPendingLOD for LOD request  //                                 push LODRequest to mLODReqQ  //                             ... @@ -246,7 +248,6 @@  //     sActiveLODRequests       mMutex        rw.any.mMutex, ro.repo.none [1]  //     sMaxConcurrentRequests   mMutex        wo.main.none, ro.repo.none, ro.main.mMutex  //     mMeshHeader              mHeaderMutex  rw.repo.mHeaderMutex, ro.main.mHeaderMutex, ro.main.none [0] -//     mMeshHeaderSize          mHeaderMutex  rw.repo.mHeaderMutex  //     mSkinRequests            mMutex        rw.repo.mMutex, ro.repo.none [5]  //     mSkinInfoQ               mMutex        rw.repo.mMutex, rw.main.mMutex [5] (was:  [0])  //     mDecompositionRequests   mMutex        rw.repo.mMutex, ro.repo.none [5] @@ -858,6 +859,12 @@ LLMeshRepoThread::~LLMeshRepoThread()  	mHttpRequestSet.clear();      mHttpHeaders.reset(); +	while (!mSkinInfoQ.empty()) +    { +        delete mSkinInfoQ.front(); +        mSkinInfoQ.pop_front(); +    } +      while (!mDecompositionQ.empty())      {          delete mDecompositionQ.front(); @@ -947,7 +954,8 @@ void LLMeshRepoThread::run()                      else                      {                          // too many fails -                        mUnavailableQ.push(req); +						LLMutexLock lock(mMutex); +                        mUnavailableQ.push_back(req);                          LL_WARNS() << "Failed to load " << req.mMeshParams << " , skip" << LL_ENDL;                      }                  } @@ -1023,37 +1031,42 @@ void LLMeshRepoThread::run()              if (!mSkinRequests.empty())              { -                std::set<UUIDBasedRequest> incomplete; -                while (!mSkinRequests.empty() && mHttpRequestSet.size() < sRequestHighWater) -                { -                    mMutex->lock(); -                    std::set<UUIDBasedRequest>::iterator iter = mSkinRequests.begin(); -                    UUIDBasedRequest req = *iter; -                    mSkinRequests.erase(iter); -                    mMutex->unlock(); -                    if (req.isDelayed()) -                    { -                        incomplete.insert(req); -                    } -                    else if (!fetchMeshSkinInfo(req.mId)) -                    { -                        if (req.canRetry()) -                        { -                            req.updateTime(); -                            incomplete.insert(req); -                        } -                        else -                        { -                            LL_DEBUGS() << "mSkinRequests failed: " << req.mId << LL_ENDL; -                        } -                    } -                } +				std::list<UUIDBasedRequest> incomplete; +				while (!mSkinRequests.empty() && mHttpRequestSet.size() < sRequestHighWater) +				{ -                if (!incomplete.empty()) -                { -                    LLMutexLock locker(mMutex); -                    mSkinRequests.insert(incomplete.begin(), incomplete.end()); -                } +					mMutex->lock(); +					auto req = mSkinRequests.front(); +					mSkinRequests.pop_front(); +					mMutex->unlock(); +					if (req.isDelayed()) +					{ +						incomplete.emplace_back(req); +					} +					else if (!fetchMeshSkinInfo(req.mId, req.canRetry())) +					{ +						if (req.canRetry()) +						{ +							req.updateTime(); +							incomplete.emplace_back(req); +						} +						else +						{ +							LLMutexLock locker(mMutex); +							mSkinUnavailableQ.push_back(req); +							LL_DEBUGS() << "mSkinReqQ failed: " << req.mId << LL_ENDL; +						} +					} +				} + +				if (!incomplete.empty()) +				{ +					LLMutexLock locker(mMutex); +					for (const auto& req : incomplete) +					{ +						mSkinRequests.push_back(req); +					} +				}              }              // holding lock, try next list @@ -1152,7 +1165,7 @@ void LLMeshRepoThread::run()  // Mutex:  LLMeshRepoThread::mMutex must be held on entry  void LLMeshRepoThread::loadMeshSkinInfo(const LLUUID& mesh_id)  { -	mSkinRequests.insert(UUIDBasedRequest(mesh_id)); +	mSkinRequests.push_back(UUIDBasedRequest(mesh_id));  }  // Mutex:  LLMeshRepoThread::mMutex must be held on entry @@ -1178,10 +1191,13 @@ void LLMeshRepoThread::lockAndLoadMeshLOD(const LLVolumeParams& mesh_params, S32  void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod)  { //could be called from any thread +	const LLUUID& mesh_id = mesh_params.getSculptID();  	LLMutexLock lock(mMutex); -	mesh_header_map::iterator iter = mMeshHeader.find(mesh_params.getSculptID()); +	LLMutexLock header_lock(mHeaderMutex); +	mesh_header_map::iterator iter = mMeshHeader.find(mesh_id);  	if (iter != mMeshHeader.end())  	{ //if we have the header, request LOD byte range +  		LODRequest req(mesh_params, lod);  		{  			mLODReqQ.push(req); @@ -1191,8 +1207,7 @@ void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod)  	else  	{   		HeaderRequest req(mesh_params); -		 -		pending_lod_map::iterator pending = mPendingLOD.find(mesh_params); +		pending_lod_map::iterator pending = mPendingLOD.find(mesh_id);  		if (pending != mPendingLOD.end())  		{ //append this lod request to existing header request @@ -1202,7 +1217,7 @@ void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod)  		else  		{ //if no header request is pending, fetch header  			mHeaderReqQ.push(req); -			mPendingLOD[mesh_params].push_back(lod); +			mPendingLOD[mesh_id].push_back(lod);  		}  	}  } @@ -1307,7 +1322,7 @@ LLCore::HttpHandle LLMeshRepoThread::getByteRange(const std::string & url,  } -bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) +bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id, bool can_retry)  {  	if (!mHeaderMutex) @@ -1317,7 +1332,8 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)  	mHeaderMutex->lock(); -	if (mMeshHeader.find(mesh_id) == mMeshHeader.end()) +	auto header_it = mMeshHeader.find(mesh_id); +	if (header_it == mMeshHeader.end())  	{ //we have no header info for this mesh, do nothing  		mHeaderMutex->unlock();  		return false; @@ -1325,13 +1341,14 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)  	++LLMeshRepository::sMeshRequestCount;  	bool ret = true; -	U32 header_size = mMeshHeaderSize[mesh_id]; +	U32 header_size = header_it->second.first;  	if (header_size > 0)  	{ -		S32 version = mMeshHeader[mesh_id]["version"].asInteger(); -		S32 offset = header_size + mMeshHeader[mesh_id]["skin"]["offset"].asInteger(); -		S32 size = mMeshHeader[mesh_id]["skin"]["size"].asInteger(); +		const LLSD& header = header_it->second.second; +		S32 version = header["version"].asInteger(); +		S32 offset = header_size + header["skin"]["offset"].asInteger(); +		S32 size = header["skin"]["size"].asInteger();  		mHeaderMutex->unlock(); @@ -1387,12 +1404,27 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)  									   << LL_ENDL;  					ret = false;  				} -				else +				else if(can_retry)  				{  					handler->mHttpHandle = handle;  					mHttpRequestSet.insert(handler);  				} +				else +				{ +					LLMutexLock locker(mMutex); +					mSkinUnavailableQ.emplace_back(mesh_id); +				}  			} +			else +			{ +				LLMutexLock locker(mMutex); +				mSkinUnavailableQ.emplace_back(mesh_id); +			} +		} +		else +		{ +			LLMutexLock locker(mMutex); +			mSkinUnavailableQ.emplace_back(mesh_id);  		}  	}  	else @@ -1413,21 +1445,23 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)  	mHeaderMutex->lock(); -	if (mMeshHeader.find(mesh_id) == mMeshHeader.end()) +	auto header_it = mMeshHeader.find(mesh_id); +	if (header_it == mMeshHeader.end())  	{ //we have no header info for this mesh, do nothing  		mHeaderMutex->unlock();  		return false;  	}  	++LLMeshRepository::sMeshRequestCount; -	U32 header_size = mMeshHeaderSize[mesh_id]; +	U32 header_size = header_it->second.first;  	bool ret = true;  	if (header_size > 0)  	{ -		S32 version = mMeshHeader[mesh_id]["version"].asInteger(); -		S32 offset = header_size + mMeshHeader[mesh_id]["physics_convex"]["offset"].asInteger(); -		S32 size = mMeshHeader[mesh_id]["physics_convex"]["size"].asInteger(); +		const auto& header = header_it->second.second; +		S32 version = header["version"].asInteger(); +		S32 offset = header_size + header["physics_convex"]["offset"].asInteger(); +		S32 size = header["physics_convex"]["size"].asInteger();  		mHeaderMutex->unlock(); @@ -1510,21 +1544,23 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)  	mHeaderMutex->lock(); -	if (mMeshHeader.find(mesh_id) == mMeshHeader.end()) +	auto header_it = mMeshHeader.find(mesh_id); +	if (header_it == mMeshHeader.end())  	{ //we have no header info for this mesh, do nothing  		mHeaderMutex->unlock();  		return false;  	}  	++LLMeshRepository::sMeshRequestCount; -	U32 header_size = mMeshHeaderSize[mesh_id]; +	U32 header_size = header_it->second.first;  	bool ret = true;  	if (header_size > 0)  	{ -		S32 version = mMeshHeader[mesh_id]["version"].asInteger(); -		S32 offset = header_size + mMeshHeader[mesh_id]["physics_mesh"]["offset"].asInteger(); -		S32 size = mMeshHeader[mesh_id]["physics_mesh"]["size"].asInteger(); +		const auto& header = header_it->second.second; +		S32 version = header["version"].asInteger(); +		S32 offset = header_size + header["physics_mesh"]["offset"].asInteger(); +		S32 size = header["physics_mesh"]["size"].asInteger();  		mHeaderMutex->unlock(); @@ -1704,20 +1740,25 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod,  		return false;  	} -	mHeaderMutex->lock(); +	const LLUUID& mesh_id = mesh_params.getSculptID(); +	mHeaderMutex->lock(); +	auto header_it = mMeshHeader.find(mesh_id); +	if (header_it == mMeshHeader.end()) +	{ //we have no header info for this mesh, do nothing +		mHeaderMutex->unlock(); +		return false; +	}  	++LLMeshRepository::sMeshRequestCount;  	bool retval = true; - -	LLUUID mesh_id = mesh_params.getSculptID(); -	U32 header_size = mMeshHeaderSize[mesh_id]; - +	U32 header_size = header_it->second.first;  	if (header_size > 0)  	{ -		S32 version = mMeshHeader[mesh_id]["version"].asInteger(); -		S32 offset = header_size + mMeshHeader[mesh_id][header_lod[lod]]["offset"].asInteger(); -		S32 size = mMeshHeader[mesh_id][header_lod[lod]]["size"].asInteger(); +		const auto& header = header_it->second.second; +		S32 version = header["version"].asInteger(); +		S32 offset = header_size + header[header_lod[lod]]["offset"].asInteger(); +		S32 size = header[header_lod[lod]]["size"].asInteger();  		mHeaderMutex->unlock();  		if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0) @@ -1792,17 +1833,20 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod,  				}  				else  				{ -					mUnavailableQ.push(LODRequest(mesh_params, lod)); +					LLMutexLock lock(mMutex); +					mUnavailableQ.push_back(LODRequest(mesh_params, lod));  				}  			}  			else  			{ -				mUnavailableQ.push(LODRequest(mesh_params, lod)); +				LLMutexLock lock(mMutex); +				mUnavailableQ.push_back(LODRequest(mesh_params, lod));  			}  		}  		else  		{ -			mUnavailableQ.push(LODRequest(mesh_params, lod)); +			LLMutexLock lock(mMutex); +			mUnavailableQ.push_back(LODRequest(mesh_params, lod));  		}  	}  	else @@ -1821,27 +1865,12 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes  	U32 header_size = 0;  	if (data_size > 0)  	{ -        std::istringstream stream; -        try -        { -            std::string res_str((char*)data, data_size); +		U32 dsize = data_size; +		char* result_ptr = strip_deprecated_header((char*)data, dsize, &header_size); -            std::string deprecated_header("<? LLSD/Binary ?>"); +		data_size = dsize; -            if (res_str.substr(0, deprecated_header.size()) == deprecated_header) -            { -                res_str = res_str.substr(deprecated_header.size() + 1, data_size); -                header_size = deprecated_header.size() + 1; -            } -            data_size = res_str.size(); - -            stream.str(res_str); -        } -        catch (std::bad_alloc&) -        { -            // out of memory, we won't be able to process this mesh -            return MESH_OUT_OF_MEMORY; -        } +		boost::iostreams::stream<boost::iostreams::array_source> stream(result_ptr, data_size);  		if (!LLSDSerialize::fromBinary(header, stream, data_size))  		{ @@ -1878,8 +1907,7 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes  		{  			LLMutexLock lock(mHeaderMutex); -			mMeshHeaderSize[mesh_id] = header_size; -			mMeshHeader[mesh_id] = header; +			mMeshHeader[mesh_id] = { header_size, header };              LLMeshRepository::sCacheBytesHeaders += header_size;  		} @@ -1887,7 +1915,7 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes  		LLMutexLock lock(mMutex); // make sure only one thread access mPendingLOD at the same time.  		//check for pending requests -		pending_lod_map::iterator iter = mPendingLOD.find(mesh_params); +		pending_lod_map::iterator iter = mPendingLOD.find(mesh_id);  		if (iter != mPendingLOD.end())  		{  			for (U32 i = 0; i < iter->second.size(); ++i) @@ -1911,26 +1939,14 @@ EMeshProcessingResult LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_p  	}  	LLPointer<LLVolume> volume = new LLVolume(mesh_params, LLVolumeLODGroup::getVolumeScaleFromDetail(lod)); -	std::istringstream stream; -	try -	{ -		std::string mesh_string((char*)data, data_size); -		stream.str(mesh_string); -	} -	catch (std::bad_alloc&) -	{ -		// out of memory, we won't be able to process this mesh -		return MESH_OUT_OF_MEMORY; -	} - -	if (volume->unpackVolumeFaces(stream, data_size)) +	if (volume->unpackVolumeFaces(data, data_size))  	{  		if (volume->getNumFaces() > 0)  		{  			LoadedMesh mesh(volume, mesh_params, lod);  			{  				LLMutexLock lock(mMutex); -				mLoadedQ.push(mesh); +				mLoadedQ.push_back(mesh);  				// LLPointer is not thread safe, since we added this pointer into  				// threaded list, make sure counter gets decreased inside mutex lock  				// and won't affect mLoadedQ processing @@ -1953,10 +1969,7 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat  	{          try          { -            std::string res_str((char*)data, data_size); -            std::istringstream stream(res_str); - -            U32 uzip_result = LLUZipHelper::unzip_llsd(skin, stream, data_size); +            U32 uzip_result = LLUZipHelper::unzip_llsd(skin, data, data_size);              if (uzip_result != LLUZipHelper::ZR_OK)              {                  LL_WARNS(LOG_MESH) << "Mesh skin info parse error.  Not a valid mesh asset!  ID:  " << mesh_id @@ -1973,8 +1986,16 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat  	}  	{ -		LLMeshSkinInfo info(skin); -		info.mMeshID = mesh_id; +		LLMeshSkinInfo* info = nullptr; +		try +		{ +			info = new LLMeshSkinInfo(mesh_id, skin); +		} +		catch (const std::bad_alloc& ex) +		{ +			LL_WARNS() << "Failed to allocate skin info with exception: " << ex.what()  << LL_ENDL; +			return false; +		}          // LL_DEBUGS(LOG_MESH) << "info pelvis offset" << info.mPelvisOffset << LL_ENDL;  		{ @@ -1994,10 +2015,7 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3      {          try          { -            std::string res_str((char*)data, data_size); -            std::istringstream stream(res_str); - -            U32 uzip_result = LLUZipHelper::unzip_llsd(decomp, stream, data_size); +            U32 uzip_result = LLUZipHelper::unzip_llsd(decomp, data, data_size);              if (uzip_result != LLUZipHelper::ZR_OK)              {                  LL_WARNS(LOG_MESH) << "Mesh decomposition parse error.  Not a valid mesh asset!  ID:  " << mesh_id @@ -2006,7 +2024,7 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3                  return false;              }          } -        catch (std::bad_alloc&) +        catch (const std::bad_alloc&)          {              LL_WARNS(LOG_MESH) << "Out of memory for mesh ID " << mesh_id << " of size: " << data_size << LL_ENDL;              return false; @@ -2043,20 +2061,7 @@ EMeshProcessingResult LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_  		volume_params.setSculptID(mesh_id, LL_SCULPT_TYPE_MESH);  		LLPointer<LLVolume> volume = new LLVolume(volume_params,0); -        std::istringstream stream; -        try -        { -            std::string mesh_string((char*)data, data_size); -            stream.str(mesh_string); -        } -        catch (std::bad_alloc&) -        { -            // out of memory, we won't be able to process this mesh -            delete d; -            return MESH_OUT_OF_MEMORY; -        } - -		if (volume->unpackVolumeFaces(stream, data_size)) +		if (volume->unpackVolumeFaces(data, data_size))  		{  			d->mPhysicsShapeMesh.clear(); @@ -2870,58 +2875,72 @@ void LLMeshRepoThread::notifyLoadedMeshes()  		return;  	} -	while (!mLoadedQ.empty()) +	if (!mLoadedQ.empty())  	{ +		std::deque<LoadedMesh> loaded_queue; +  		mMutex->lock(); -		if (mLoadedQ.empty()) +		if (!mLoadedQ.empty())  		{ +			loaded_queue.swap(mLoadedQ);  			mMutex->unlock(); -			break; -		} -		LoadedMesh mesh = mLoadedQ.front(); // make sure nothing else owns volume pointer by this point -		mLoadedQ.pop(); -		mMutex->unlock(); -		 -		update_metrics = true; -		if (mesh.mVolume->getNumVolumeFaces() > 0) -		{ -			gMeshRepo.notifyMeshLoaded(mesh.mMeshParams, mesh.mVolume); -		} -		else -		{ -			gMeshRepo.notifyMeshUnavailable(mesh.mMeshParams,  -				LLVolumeLODGroup::getVolumeDetailFromScale(mesh.mVolume->getDetail())); + +			update_metrics = true; + +			// Process the elements free of the lock +			for (const auto& mesh : loaded_queue) +			{ +				if (mesh.mVolume->getNumVolumeFaces() > 0) +				{ +					gMeshRepo.notifyMeshLoaded(mesh.mMeshParams, mesh.mVolume); +				} +				else +				{ +					gMeshRepo.notifyMeshUnavailable(mesh.mMeshParams, +						LLVolumeLODGroup::getVolumeDetailFromScale(mesh.mVolume->getDetail())); +				} +			}  		}  	} -	while (!mUnavailableQ.empty()) +	if (!mUnavailableQ.empty())  	{ +		std::deque<LODRequest> unavil_queue; +  		mMutex->lock(); -		if (mUnavailableQ.empty()) +		if (!mUnavailableQ.empty())  		{ +			unavil_queue.swap(mUnavailableQ);  			mMutex->unlock(); -			break; -		} -		 -		LODRequest req = mUnavailableQ.front(); -		mUnavailableQ.pop(); -		mMutex->unlock(); -		update_metrics = true; -		gMeshRepo.notifyMeshUnavailable(req.mMeshParams, req.mLOD); +			update_metrics = true; + +			// Process the elements free of the lock +			for (const auto& req : unavil_queue) +			{ +				gMeshRepo.notifyMeshUnavailable(req.mMeshParams, req.mLOD); +			} +		}  	} -	if (! mSkinInfoQ.empty() || ! mDecompositionQ.empty()) +	if (!mSkinInfoQ.empty() || !mSkinUnavailableQ.empty() || ! mDecompositionQ.empty())  	{  		if (mMutex->trylock())  		{ -			std::list<LLMeshSkinInfo> skin_info_q; +			std::deque<LLMeshSkinInfo*> skin_info_q; +			std::deque<UUIDBasedRequest> skin_info_unavail_q;  			std::list<LLModel::Decomposition*> decomp_q;  			if (! mSkinInfoQ.empty())  			{  				skin_info_q.swap(mSkinInfoQ);  			} + +			if (! mSkinUnavailableQ.empty()) +			{ +				skin_info_unavail_q.swap(mSkinUnavailableQ); +			} +  			if (! mDecompositionQ.empty())  			{  				decomp_q.swap(mDecompositionQ); @@ -2935,6 +2954,11 @@ void LLMeshRepoThread::notifyLoadedMeshes()  				gMeshRepo.notifySkinInfoReceived(skin_info_q.front());  				skin_info_q.pop_front();  			} +			while (! skin_info_unavail_q.empty()) +			{ +				gMeshRepo.notifySkinInfoUnavailable(skin_info_unavail_q.front().mId); +				skin_info_unavail_q.pop_front(); +			}  			while (! decomp_q.empty())  			{ @@ -2959,7 +2983,7 @@ S32 LLMeshRepoThread::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lo  	if (iter != mMeshHeader.end())  	{ -		LLSD& header = iter->second; +		LLSD& header = iter->second.second;  		return LLMeshRepository::getActualMeshLOD(header, lod);  	} @@ -3162,7 +3186,7 @@ void LLMeshHeaderHandler::processFailure(LLCore::HttpStatus status)  	LLMutexLock lock(gMeshRepo.mThread->mMutex);  	for (int i(0); i < 4; ++i)  	{ -		gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, i)); +		gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, i));  	}  } @@ -3191,7 +3215,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b  		LLMutexLock lock(gMeshRepo.mThread->mMutex);  		for (int i(0); i < 4; ++i)  		{ -			gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, i)); +			gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, i));  		}  	}  	else if (data && data_size > 0) @@ -3204,8 +3228,8 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b  		LLMeshRepoThread::mesh_header_map::iterator iter = gMeshRepo.mThread->mMeshHeader.find(mesh_id);  		if (iter != gMeshRepo.mThread->mMeshHeader.end())  		{ -			header_bytes = (S32)gMeshRepo.mThread->mMeshHeaderSize[mesh_id]; -			header = iter->second; +			header_bytes = (S32)iter->second.first; +			header = iter->second.second;  		}  		if (header_bytes > 0 @@ -3273,7 +3297,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b  			LLMutexLock lock(gMeshRepo.mThread->mMutex);  			for (int i(0); i < 4; ++i)  			{ -				gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, i)); +				gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, i));  			}  		}  	} @@ -3300,7 +3324,7 @@ void LLMeshLODHandler::processFailure(LLCore::HttpStatus status)  					   << LL_ENDL;  	LLMutexLock lock(gMeshRepo.mThread->mMutex); -	gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, mLOD)); +	gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, mLOD));  }  void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */, @@ -3337,7 +3361,7 @@ void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body  							   << " Not retrying."  							   << LL_ENDL;  			LLMutexLock lock(gMeshRepo.mThread->mMutex); -			gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, mLOD)); +			gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, mLOD));  		}  	}  	else @@ -3348,7 +3372,7 @@ void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body  						   << " Data size: " << data_size  						   << LL_ENDL;  		LLMutexLock lock(gMeshRepo.mThread->mMutex); -		gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, mLOD)); +		gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, mLOD));  	}  } @@ -3366,9 +3390,8 @@ void LLMeshSkinInfoHandler::processFailure(LLCore::HttpStatus status)  					   << ", Reason:  " << status.toString()  					   << " (" << status.toTerseString() << ").  Not retrying."  					   << LL_ENDL; - -	// *TODO:  Mark mesh unavailable on error.  For now, simply leave -	// request unfulfilled rather than retry forever. +		LLMutexLock lock(gMeshRepo.mThread->mMutex); +		gMeshRepo.mThread->mSkinUnavailableQ.emplace_back(mMeshID);  }  void LLMeshSkinInfoHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */, @@ -3399,7 +3422,8 @@ void LLMeshSkinInfoHandler::processData(LLCore::BufferArray * /* body */, S32 /*  		LL_WARNS(LOG_MESH) << "Error during mesh skin info processing.  ID:  " << mMeshID  						   << ", Unknown reason.  Not retrying."  						   << LL_ENDL; -		// *TODO:  Mark mesh unavailable on error +		LLMutexLock lock(gMeshRepo.mThread->mMutex); +		gMeshRepo.mThread->mSkinUnavailableQ.emplace_back(mMeshID);  	}  } @@ -3508,7 +3532,7 @@ LLMeshRepository::LLMeshRepository()    mMeshThreadCount(0),    mThread(NULL)  { - +	mSkinInfoCullTimer.resetWithExpiry(10.f);  }  void LLMeshRepository::init() @@ -3609,6 +3633,22 @@ S32 LLMeshRepository::update()  	return size ;  } +void LLMeshRepository::unregisterMesh(LLVOVolume* vobj) +{ +	for (auto& lod : mLoadingMeshes) +	{ +		for (auto& param : lod) +		{ +			vector_replace_with_last(param.second, vobj); +		} +	} + +	for (auto& skin_pair : mLoadingSkins) +	{ +		vector_replace_with_last(skin_pair.second, vobj); +	} +} +  S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail, S32 last_lod)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH); @@ -3624,15 +3664,19 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para  	{  		LLMutexLock lock(mMeshMutex);  		//add volume to list of loading meshes -		mesh_load_map::iterator iter = mLoadingMeshes[detail].find(mesh_params); +		const auto& mesh_id = mesh_params.getSculptID(); +		mesh_load_map::iterator iter = mLoadingMeshes[detail].find(mesh_id);  		if (iter != mLoadingMeshes[detail].end())  		{ //request pending for this mesh, append volume id to list -			iter->second.insert(vobj->getID()); +			auto it = std::find(iter->second.begin(), iter->second.end(), vobj); +			if (it == iter->second.end()) { +				iter->second.push_back(vobj); +			}  		}  		else  		{  			//first request for this mesh -			mLoadingMeshes[detail][mesh_params].insert(vobj->getID()); +			mLoadingMeshes[detail][mesh_id].push_back(vobj);  			mPendingRequests.push_back(LLMeshRepoThread::LODRequest(mesh_params, detail));  			LLMeshRepository::sLODPending++;  		} @@ -3789,6 +3833,28 @@ void LLMeshRepository::notifyLoadedMeshes()  	//call completed callbacks on finished decompositions  	mDecompThread->notifyCompleted(); +	if (mSkinInfoCullTimer.checkExpirationAndReset(10.f))  +	{ +		//// Clean up dead skin info +		//U64Bytes skinbytes(0); +		for (auto iter = mSkinMap.begin(), ender = mSkinMap.end(); iter != ender;) +		{ +			auto copy_iter = iter++; + +			//skinbytes += U64Bytes(sizeof(LLMeshSkinInfo)); +			//skinbytes += U64Bytes(copy_iter->second->mJointNames.size() * sizeof(std::string)); +			//skinbytes += U64Bytes(copy_iter->second->mJointNums.size() * sizeof(S32)); +			//skinbytes += U64Bytes(copy_iter->second->mJointNames.size() * sizeof(LLMatrix4a)); +			//skinbytes += U64Bytes(copy_iter->second->mJointNames.size() * sizeof(LLMatrix4)); + +			if (copy_iter->second->getNumRefs() == 1) +			{ +				mSkinMap.erase(copy_iter); +			} +		} +		//LL_INFOS() << "Skin info cache elements:" << mSkinMap.size() << " Memory: " << U64Kilobytes(skinbytes) << LL_ENDL; +	} +  	// For major operations, attempt to get the required locks  	// without blocking and punt if they're not available.  The  	// longest run of holdoffs is kept in sMaxLockHoldoffs just @@ -3859,10 +3925,9 @@ void LLMeshRepository::notifyLoadedMeshes()  					for (mesh_load_map::iterator iter = mLoadingMeshes[i].begin();  iter != mLoadingMeshes[i].end(); ++iter)  					{  						F32 max_score = 0.f; -						for (std::set<LLUUID>::iterator obj_iter = iter->second.begin(); obj_iter != iter->second.end(); ++obj_iter) +						for (auto obj_iter = iter->second.begin(); obj_iter != iter->second.end(); ++obj_iter)  						{ -							LLViewerObject* object = gObjectList.findObject(*obj_iter); -							 +							LLVOVolume* object = *obj_iter;						  							if (object)  							{  								LLDrawable* drawable = object->mDrawable; @@ -3874,7 +3939,7 @@ void LLMeshRepository::notifyLoadedMeshes()  							}  						} -						score_map[iter->first.getSculptID()] = max_score; +						score_map[iter->first] = max_score;  					}  				} @@ -3926,24 +3991,39 @@ void LLMeshRepository::notifyLoadedMeshes()  	mThread->mSignal->signal();  } -void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo& info) +void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo* info)  { -	mSkinMap[info.mMeshID] = info; +	mSkinMap[info->mMeshID] = info; // Cache into LLPointer      // Alternative: We can get skin size from header -    sCacheBytesSkins += info.sizeBytes(); +    sCacheBytesSkins += info->sizeBytes(); -	skin_load_map::iterator iter = mLoadingSkins.find(info.mMeshID); +	skin_load_map::iterator iter = mLoadingSkins.find(info->mMeshID);  	if (iter != mLoadingSkins.end())  	{ -		for (std::set<LLUUID>::iterator obj_id = iter->second.begin(); obj_id != iter->second.end(); ++obj_id) +		for (LLVOVolume* vobj : iter->second)  		{ -			LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*obj_id);  			if (vobj)  			{ -				vobj->notifyMeshLoaded(); +				vobj->notifySkinInfoLoaded(info);  			}  		} -		mLoadingSkins.erase(info.mMeshID); +		mLoadingSkins.erase(iter); +	} +} + +void LLMeshRepository::notifySkinInfoUnavailable(const LLUUID& mesh_id) +{ +	skin_load_map::iterator iter = mLoadingSkins.find(mesh_id); +	if (iter != mLoadingSkins.end()) +	{ +		for (LLVOVolume* vobj : iter->second) +		{ +			if (vobj) +			{ +				vobj->notifySkinInfoUnavailable(); +			} +		} +		mLoadingSkins.erase(iter);  	}  } @@ -3972,14 +4052,15 @@ void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVol  	S32 detail = LLVolumeLODGroup::getVolumeDetailFromScale(volume->getDetail());  	//get list of objects waiting to be notified this mesh is loaded -	mesh_load_map::iterator obj_iter = mLoadingMeshes[detail].find(mesh_params); +	const auto& mesh_id = mesh_params.getSculptID(); +	mesh_load_map::iterator obj_iter = mLoadingMeshes[detail].find(mesh_id);  	if (volume && obj_iter != mLoadingMeshes[detail].end())  	{  		//make sure target volume is still valid  		if (volume->getNumVolumeFaces() <= 0)  		{ -			LL_WARNS(LOG_MESH) << "Mesh loading returned empty volume.  ID:  " << mesh_params.getSculptID() +			LL_WARNS(LOG_MESH) << "Mesh loading returned empty volume.  ID:  " << mesh_id  							   << LL_ENDL;  		} @@ -3993,37 +4074,35 @@ void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVol  			}  			else  			{ -				LL_WARNS(LOG_MESH) << "Couldn't find system volume for mesh " << mesh_params.getSculptID() +				LL_WARNS(LOG_MESH) << "Couldn't find system volume for mesh " << mesh_id  								   << LL_ENDL;  			}  		}  		//notify waiting LLVOVolume instances that their requested mesh is available -		for (std::set<LLUUID>::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter) +		for (LLVOVolume* vobj : obj_iter->second)  		{ -			LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*vobj_iter);  			if (vobj)  			{  				vobj->notifyMeshLoaded();  			}  		} -		mLoadingMeshes[detail].erase(mesh_params); +		mLoadingMeshes[detail].erase(obj_iter);  	}  }  void LLMeshRepository::notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 lod)  { //called from main thread  	//get list of objects waiting to be notified this mesh is loaded -	mesh_load_map::iterator obj_iter = mLoadingMeshes[lod].find(mesh_params); - -	F32 detail = LLVolumeLODGroup::getVolumeScaleFromDetail(lod); - +	const auto& mesh_id = mesh_params.getSculptID(); +	mesh_load_map::iterator obj_iter = mLoadingMeshes[lod].find(mesh_id);  	if (obj_iter != mLoadingMeshes[lod].end())  	{ -		for (std::set<LLUUID>::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter) +		F32 detail = LLVolumeLODGroup::getVolumeScaleFromDetail(lod); + +		for (LLVOVolume* vobj : obj_iter->second)  		{ -			LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*vobj_iter);  			if (vobj)  			{  				LLVolume* obj_volume = vobj->getVolume(); @@ -4037,7 +4116,7 @@ void LLMeshRepository::notifyMeshUnavailable(const LLVolumeParams& mesh_params,  			}  		} -		mLoadingMeshes[lod].erase(mesh_params); +		mLoadingMeshes[lod].erase(obj_iter);  	}  } @@ -4046,7 +4125,7 @@ S32 LLMeshRepository::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lo  	return mThread->getActualMeshLOD(mesh_params, lod);  } -const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const LLVOVolume* requesting_obj) +const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, LLVOVolume* requesting_obj)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;      if (mesh_id.notNull()) @@ -4054,7 +4133,7 @@ const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const          skin_map::iterator iter = mSkinMap.find(mesh_id);          if (iter != mSkinMap.end())          { -            return &(iter->second); +            return iter->second;          }          //no skin info known about given mesh, try to fetch it @@ -4063,14 +4142,22 @@ const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const              LLMutexLock lock(mMeshMutex);              //add volume to list of loading meshes              skin_load_map::iterator iter = mLoadingSkins.find(mesh_id); -            if (iter == mLoadingSkins.end()) -            { //no request pending for this skin info +			if (iter != mLoadingSkins.end()) +			{ //request pending for this mesh, append volume id to list +				auto it = std::find(iter->second.begin(), iter->second.end(), requesting_obj); +				if (it == iter->second.end()) { +					iter->second.push_back(requesting_obj); +				} +			} +			else +			{ +				//first request for this mesh +				mLoadingSkins[mesh_id].push_back(requesting_obj);                  mPendingSkinRequests.push(mesh_id);              } -            mLoadingSkins[mesh_id].insert(requesting_obj->getID());          }      } -	return NULL; +	return nullptr;  }  void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id) @@ -4173,16 +4260,13 @@ bool LLMeshRepository::hasPhysicsShape(const LLUUID& mesh_id)  bool LLMeshRepoThread::hasPhysicsShapeInHeader(const LLUUID& mesh_id)  {      LLMutexLock lock(mHeaderMutex); -    if (mMeshHeaderSize[mesh_id] > 0) +    mesh_header_map::iterator iter = mMeshHeader.find(mesh_id); +    if (iter != mMeshHeader.end() && iter->second.first > 0)      { -        mesh_header_map::iterator iter = mMeshHeader.find(mesh_id); -        if (iter != mMeshHeader.end()) +        LLSD &mesh = iter->second.second; +        if (mesh.has("physics_mesh") && mesh["physics_mesh"].has("size") && (mesh["physics_mesh"]["size"].asInteger() > 0))          { -            LLSD &mesh = iter->second; -            if (mesh.has("physics_mesh") && mesh["physics_mesh"].has("size") && (mesh["physics_mesh"]["size"].asInteger() > 0)) -            { -                return true; -            } +            return true;          }      } @@ -4207,9 +4291,9 @@ S32 LLMeshRepository::getMeshSize(const LLUUID& mesh_id, S32 lod)  	{  		LLMutexLock lock(mThread->mHeaderMutex);  		LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); -		if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0) +		if (iter != mThread->mMeshHeader.end() && iter->second.first > 0)  		{ -			LLSD& header = iter->second; +			const LLSD& header = iter->second.second;  			if (header.has("404"))  			{ @@ -4313,9 +4397,9 @@ F32 LLMeshRepository::getStreamingCostLegacy(LLUUID mesh_id, F32 radius, S32* by      {          LLMutexLock lock(mThread->mHeaderMutex);          LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); -        if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0) +        if (iter != mThread->mMeshHeader.end() && iter->second.first > 0)          { -            result  = getStreamingCostLegacy(iter->second, radius, bytes, bytes_visible, lod, unscaled_value); +            result  = getStreamingCostLegacy(iter->second.second, radius, bytes, bytes_visible, lod, unscaled_value);          }      }      if (result > 0.f) @@ -4628,9 +4712,9 @@ bool LLMeshRepository::getCostData(LLUUID mesh_id, LLMeshCostData& data)      {          LLMutexLock lock(mThread->mHeaderMutex);          LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); -        if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0) +        if (iter != mThread->mMeshHeader.end() && iter->second.first > 0)          { -            LLSD& header = iter->second; +            LLSD& header = iter->second.second;              bool header_invalid = (header.has("404")                                     || !header.has("lowest_lod") diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index f61da3e571..e3688ff243 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -210,10 +210,8 @@ public:  	LLCondition* mSignal;  	//map of known mesh headers -	typedef std::map<LLUUID, LLSD> mesh_header_map; +	typedef boost::unordered_map<LLUUID, std::pair<U32, LLSD>> mesh_header_map; // pair is header_size and data  	mesh_header_map mMeshHeader; -	 -	std::map<LLUUID, U32> mMeshHeaderSize;  	class HeaderRequest : public RequestStats  	{  @@ -283,10 +281,13 @@ public:  	};  	//set of requested skin info -	std::set<UUIDBasedRequest> mSkinRequests; +	std::deque<UUIDBasedRequest> mSkinRequests;  	// list of completed skin info requests -	std::list<LLMeshSkinInfo> mSkinInfoQ; +	std::deque<LLMeshSkinInfo*> mSkinInfoQ; + +	// list of skin info requests that have failed or are unavailaibe +	std::deque<UUIDBasedRequest> mSkinUnavailableQ;  	//set of requested decompositions  	std::set<UUIDBasedRequest> mDecompositionRequests; @@ -304,13 +305,13 @@ public:  	std::queue<LODRequest> mLODReqQ;  	//queue of unavailable LODs (either asset doesn't exist or asset doesn't have desired LOD) -	std::queue<LODRequest> mUnavailableQ; +	std::deque<LODRequest> mUnavailableQ;  	//queue of successfully loaded meshes -	std::queue<LoadedMesh> mLoadedQ; +	std::deque<LoadedMesh> mLoadedQ;  	//map of pending header requests and currently desired LODs -	typedef std::map<LLVolumeParams, std::vector<S32> > pending_lod_map; +	typedef boost::unordered_map<LLUUID, std::vector<S32> > pending_lod_map;  	pending_lod_map mPendingLOD;  	// llcorehttp library interface objects. @@ -354,7 +355,7 @@ public:  	//send request for skin info, returns true if header info exists   	//  (should hold onto mesh_id and try again later if header info does not exist) -	bool fetchMeshSkinInfo(const LLUUID& mesh_id); +	bool fetchMeshSkinInfo(const LLUUID& mesh_id, bool can_retry = true);  	//send request for decomposition, returns true if header info exists   	//  (should hold onto mesh_id and try again later if header info does not exist) @@ -577,18 +578,20 @@ public:  	void shutdown();  	S32 update(); +	void unregisterMesh(LLVOVolume* volume);  	//mesh management functions  	S32 loadMesh(LLVOVolume* volume, const LLVolumeParams& mesh_params, S32 detail = 0, S32 last_lod = -1);  	void notifyLoadedMeshes();  	void notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume);  	void notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 lod); -	void notifySkinInfoReceived(LLMeshSkinInfo& info); +	void notifySkinInfoReceived(LLMeshSkinInfo* info); +	void notifySkinInfoUnavailable(const LLUUID& info);  	void notifyDecompositionReceived(LLModel::Decomposition* info);  	S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);  	static S32 getActualMeshLOD(LLSD& header, S32 lod); -	const LLMeshSkinInfo* getSkinInfo(const LLUUID& mesh_id, const LLVOVolume* requesting_obj = nullptr); +	const LLMeshSkinInfo* getSkinInfo(const LLUUID& mesh_id, LLVOVolume* requesting_obj = nullptr);  	LLModel::Decomposition* getDecomposition(const LLUUID& mesh_id);  	void fetchPhysicsShape(const LLUUID& mesh_id);  	bool hasPhysicsShape(const LLUUID& mesh_id); @@ -613,10 +616,10 @@ public:  	static void metricsProgress(unsigned int count);  	static void metricsUpdate(); -	typedef std::map<LLVolumeParams, std::set<LLUUID> > mesh_load_map; +	typedef boost::unordered_map<LLUUID, std::vector<LLVOVolume*> > mesh_load_map;  	mesh_load_map mLoadingMeshes[4]; -	typedef std::unordered_map<LLUUID, LLMeshSkinInfo> skin_map; +	typedef std::unordered_map<LLUUID, LLPointer<LLMeshSkinInfo>> skin_map;  	skin_map mSkinMap;  	typedef std::map<LLUUID, LLModel::Decomposition*> decomposition_map; @@ -627,7 +630,7 @@ public:  	std::vector<LLMeshRepoThread::LODRequest> mPendingRequests;  	//list of mesh ids awaiting skin info -	typedef std::map<LLUUID, std::set<LLUUID> > skin_load_map; +	typedef boost::unordered_map<LLUUID, std::vector<LLVOVolume*> > skin_load_map;  	skin_load_map mLoadingSkins;  	//list of mesh ids that need to send skin info fetch requests @@ -652,6 +655,8 @@ public:  	std::vector<LLMeshUploadThread*> mUploadWaitList;  	LLPhysicsDecomp* mDecompThread; + +	LLFrameTimer     mSkinInfoCullTimer;  	class inventory_data  	{ diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 642df7f931..e1a5b22490 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -1926,32 +1926,16 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d                      if (sloppy_ratio < 0)                      {                          // Sloppy method didn't work, try with smaller decimation values -                        S32 size_vertices = 0; - -                        for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) -                        { -                            const LLVolumeFace &face = base->getVolumeFace(face_idx); -                            size_vertices += face.mNumVertices; -                        } - -                        // Complex models aren't supposed to get here, they are supposed -                        // to work on a first try of sloppy due to having more viggle room. -                        // If they didn't, something is likely wrong, no point locking the -                        // thread in a long calculation that will fail. -                        const U32 too_many_vertices = 27000; -                        if (size_vertices > too_many_vertices) -                        { -                            LL_WARNS() << "Sloppy optimization method failed for a complex model " << target_model->getName() << LL_ENDL; -                        } -                        else                          {                              // Find a decimator that does work                              F32 sloppy_decimation_step = sqrt((F32)decimation); // example: 27->15->9->5->3                              F32 sloppy_decimator = indices_decimator / sloppy_decimation_step; +                            U64Microseconds end_time = LLTimer::getTotalTime() + U64Seconds(5);                              while (sloppy_ratio < 0                                  && sloppy_decimator > precise_ratio -                                && sloppy_decimator > 1)// precise_ratio isn't supposed to be below 1, but check just in case +                                && sloppy_decimator > 1 // precise_ratio isn't supposed to be below 1, but check just in case +                                && end_time > LLTimer::getTotalTime())                              {                                  sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_TOPOLOGY);                                  sloppy_decimator = sloppy_decimator / sloppy_decimation_step; diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp index bf00d77dea..a7a7ed1b70 100644 --- a/indra/newview/llmutelist.cpp +++ b/indra/newview/llmutelist.cpp @@ -192,7 +192,7 @@ void LLMuteList::cleanupSingleton()      LLAvatarNameCache::getInstance()->setAccountNameChangedCallback(NULL);  } -BOOL LLMuteList::isLinden(const std::string& name) const +bool LLMuteList::isLinden(const std::string& name)  {  	std::string username = boost::replace_all_copy(name, ".", " ");  	typedef boost::tokenizer<boost::char_separator<char> > tokenizer; @@ -200,9 +200,9 @@ BOOL LLMuteList::isLinden(const std::string& name) const  	tokenizer tokens(username, sep);  	tokenizer::iterator token_iter = tokens.begin(); -	if (token_iter == tokens.end()) return FALSE; +	if (token_iter == tokens.end()) return false;  	token_iter++; -	if (token_iter == tokens.end()) return FALSE; +	if (token_iter == tokens.end()) return false;  	std::string last_name = *token_iter;  	LLStringUtil::toLower(last_name); diff --git a/indra/newview/llmutelist.h b/indra/newview/llmutelist.h index 0d426fbd48..2c45014321 100644 --- a/indra/newview/llmutelist.h +++ b/indra/newview/llmutelist.h @@ -104,7 +104,7 @@ public:  	// Alternate (convenience) form for places we don't need to pass the name, but do need flags  	BOOL isMuted(const LLUUID& id, U32 flags) const { return isMuted(id, LLStringUtil::null, flags); }; -	BOOL isLinden(const std::string& name) const; +	static bool isLinden(const std::string& name);  	BOOL isLoaded() const { return mIsLoaded; } diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index b34be80b07..0ba3c3d691 100755..100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -102,8 +102,7 @@ LLNetMap::LLNetMap (const Params & p)  	mObjectImagep(),  	mClosestAgentToCursor(),  	mClosestAgentAtLastRightClick(), -	mToolTipMsg(), -	mPopupMenu(NULL) +	mToolTipMsg()  {  	mScale = gSavedSettings.getF32("MiniMapScale");      if (gAgent.isFirstLogin()) @@ -119,6 +118,12 @@ LLNetMap::LLNetMap (const Params & p)  LLNetMap::~LLNetMap()  { +    auto menu = static_cast<LLMenuGL*>(mPopupMenuHandle.get()); +    if (menu) +    { +        menu->die(); +        mPopupMenuHandle.markDead(); +    }  }  BOOL LLNetMap::postBuild() @@ -134,11 +139,10 @@ BOOL LLNetMap::postBuild()      commitRegistrar.add("Minimap.MapOrientation.Set", boost::bind(&LLNetMap::setMapOrientation, this, _2));      commitRegistrar.add("Minimap.AboutLand", boost::bind(&LLNetMap::popupShowAboutLand, this, _2)); -    mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_mini_map.xml", gMenuHolder, -                                                                          LLViewerMenuHolderGL::child_registry_t::instance()); -    mPopupMenu->setItemEnabled("Re-center map", false); - -    return true; +    LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_mini_map.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); +    mPopupMenuHandle = menu->getHandle(); +    menu->setItemEnabled("Re-center map", false); +	return TRUE;  }  void LLNetMap::setScale( F32 scale ) @@ -206,8 +210,12 @@ void LLNetMap::draw()          mCentering = false;      } -    bool can_recenter_map = !(centered || mCentering || auto_centering); -    mPopupMenu->setItemEnabled("Re-center map", can_recenter_map); +    auto menu = static_cast<LLMenuGL*>(mPopupMenuHandle.get()); +    if (menu) +    { +        bool can_recenter_map = !(centered || mCentering || auto_centering); +        menu->setItemEnabled("Re-center map", can_recenter_map); +    }      updateAboutLandPopupButton();  	// Prepare a scissor region @@ -595,14 +603,15 @@ void LLNetMap::drawTracking(const LLVector3d& pos_global, const LLColor4& color,  bool LLNetMap::isMouseOnPopupMenu()  { -    if (!mPopupMenu->isOpen()) +    auto menu = static_cast<LLMenuGL*>(mPopupMenuHandle.get()); +    if (!menu || !menu->isOpen())      {          return false;      }      S32 popup_x;      S32 popup_y; -    LLUI::getInstance()->getMousePositionLocal(mPopupMenu, &popup_x, &popup_y); +    LLUI::getInstance()->getMousePositionLocal(menu, &popup_x, &popup_y);      // *NOTE: Tolerance is larger than it needs to be because the context menu is offset from the mouse when the menu is opened from certain      // directions. This may be a quirk of LLMenuGL::showPopup. -Cosmic,2022-03-22      constexpr S32 tolerance = 10; @@ -613,7 +622,7 @@ bool LLNetMap::isMouseOnPopupMenu()      {          for (S32 sign_y = -1; sign_y <= 1; sign_y += 2)          { -            if (mPopupMenu->pointInView(popup_x + (sign_x * tolerance), popup_y + (sign_y * tolerance))) +            if (menu->pointInView(popup_x + (sign_x * tolerance), popup_y + (sign_y * tolerance)))              {                  return true;              } @@ -624,7 +633,8 @@ bool LLNetMap::isMouseOnPopupMenu()  void LLNetMap::updateAboutLandPopupButton()  { -    if (!mPopupMenu->isOpen()) +    auto menu = static_cast<LLMenuGL*>(mPopupMenuHandle.get()); +    if (!menu || !menu->isOpen())      {          return;      } @@ -632,7 +642,7 @@ void LLNetMap::updateAboutLandPopupButton()      LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosGlobal(mPopupWorldPos);      if (!region)      { -        mPopupMenu->setItemEnabled("About Land", false); +        menu->setItemEnabled("About Land", false);      }      else      { @@ -647,7 +657,7 @@ void LLNetMap::updateAboutLandPopupButton()              {                  valid_parcel = hover_parcel->getOwnerID().notNull();              } -            mPopupMenu->setItemEnabled("About Land", valid_parcel); +            menu->setItemEnabled("About Land", valid_parcel);          }      }  } @@ -1043,13 +1053,14 @@ BOOL LLNetMap::handleMouseUp(S32 x, S32 y, MASK mask)  BOOL LLNetMap::handleRightMouseDown(S32 x, S32 y, MASK mask)  { -	if (mPopupMenu) +    auto menu = static_cast<LLMenuGL*>(mPopupMenuHandle.get()); +    if (menu)  	{ -        mPopupWorldPos = viewPosToGlobal(x, y); -		mPopupMenu->buildDrawLabels(); -		mPopupMenu->updateParent(LLMenuGL::sMenuContainer); -		mPopupMenu->setItemEnabled("Stop tracking", LLTracker::isTracking(0)); -		LLMenuGL::showPopup(this, mPopupMenu, x, y); +		mPopupWorldPos = viewPosToGlobal(x, y); +        menu->buildDrawLabels(); +        menu->updateParent(LLMenuGL::sMenuContainer); +        menu->setItemEnabled("Stop Tracking", LLTracker::isTracking(0)); +		LLMenuGL::showPopup(this, menu, x, y);  	}  	return TRUE;  } @@ -1182,9 +1193,10 @@ void LLNetMap::setZoom(const LLSD &userdata)  void LLNetMap::handleStopTracking (const LLSD& userdata)  { -	if (mPopupMenu) +    auto menu = static_cast<LLMenuGL*>(mPopupMenuHandle.get()); +    if (menu)  	{ -		mPopupMenu->setItemEnabled ("Stop tracking", false); +        menu->setItemEnabled ("Stop Tracking", false);  		LLTracker::stopTracking (LLTracker::isTracking(NULL));  	}  } diff --git a/indra/newview/llnetmap.h b/indra/newview/llnetmap.h index fe1aca65a9..75c1abc4ed 100644 --- a/indra/newview/llnetmap.h +++ b/indra/newview/llnetmap.h @@ -162,7 +162,7 @@ private:      void setMapOrientation(const LLSD& userdata);      void popupShowAboutLand(const LLSD& userdata); -	LLMenuGL*		mPopupMenu; +    LLHandle<LLView> mPopupMenuHandle;  	uuid_vec_t		gmSelected;  }; diff --git a/indra/newview/llnotificationhandlerutil.cpp b/indra/newview/llnotificationhandlerutil.cpp index 39a0b9b50e..85adfaab55 100644 --- a/indra/newview/llnotificationhandlerutil.cpp +++ b/indra/newview/llnotificationhandlerutil.cpp @@ -275,7 +275,7 @@ void LLHandlerUtil::addNotifPanelToIM(const LLNotificationPtr& notification)  	LLSD offer;  	offer["notification_id"] = notification->getID();  	offer["from"] = SYSTEM_FROM; -	offer["time"] = LLLogChat::timestamp(false); +	offer["time"] = LLLogChat::timestamp2LogString(0, false);   // Use current time  	offer["index"] = (LLSD::Integer)session->mMsgs.size();  	session->mMsgs.push_front(offer); diff --git a/indra/newview/llnotificationlistitem.cpp b/indra/newview/llnotificationlistitem.cpp index 6a79a0c68c..f86edfd0cf 100644 --- a/indra/newview/llnotificationlistitem.cpp +++ b/indra/newview/llnotificationlistitem.cpp @@ -521,8 +521,6 @@ void LLGroupNoticeNotificationListItem::close()  void LLGroupNoticeNotificationListItem::onClickAttachment()  {      if (mInventoryOffer != NULL) { -        mInventoryOffer->forceResponse(IOR_ACCEPT); -          static const LLUIColor textColor = LLUIColorTable::instance().getColor(              "GroupNotifyDimmedTextColor");          mAttachmentTextBox->setColor(textColor); @@ -532,7 +530,7 @@ void LLGroupNoticeNotificationListItem::onClickAttachment()          if (!isAttachmentOpenable(mInventoryOffer->mType)) {              LLNotifications::instance().add("AttachmentSaved", LLSD(), LLSD());          } - +        mInventoryOffer->forceResponse(IOR_ACCEPT);          mInventoryOffer = NULL;      }  } diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index 1facbbf37c..602b7412a4 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -1226,7 +1226,7 @@ void LLOutfitGallery::uploadOutfitImage(const std::vector<std::string>& filename          checkRemovePhoto(outfit_id);          std::string upload_pending_name = outfit_id.asString();          std::string upload_pending_desc = ""; -        LLUUID photo_id = upload_new_resource(filename, // file +        upload_new_resource(filename, // file              upload_pending_name,              upload_pending_desc,              0, LLFolderType::FT_NONE, LLInventoryType::IT_NONE, diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 7270580032..4171fd8822 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -823,8 +823,7 @@ void LLOutfitListBase::onOpen(const LLSD& info)          mCategoriesObserver->addCategory(outfits,              boost::bind(&LLOutfitListBase::refreshList, this, outfits)); -        const LLUUID cof = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); - +        //const LLUUID cof = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);          // Start observing changes in Current Outfit category.          //mCategoriesObserver->addCategory(cof, boost::bind(&LLOutfitsList::onCOFChanged, this)); diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index ea10aa75ae..0103bf628a 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -1663,7 +1663,7 @@ void LLPanelEditWearable::initPreviousAlphaTextureEntry(LLAvatarAppearanceDefine  class LLMetricSystemHandler : public LLCommandHandler  {  public: -        LLMetricSystemHandler() : LLCommandHandler("metricsystem", UNTRUSTED_THROTTLE) { } +        LLMetricSystemHandler() : LLCommandHandler("metricsystem", UNTRUSTED_CLICK_ONLY) { }          bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)          { diff --git a/indra/newview/llpanelexperiencelog.cpp b/indra/newview/llpanelexperiencelog.cpp index 44b4728df7..e5c637938f 100644 --- a/indra/newview/llpanelexperiencelog.cpp +++ b/indra/newview/llpanelexperiencelog.cpp @@ -112,7 +112,7 @@ void LLPanelExperienceLog::refresh()  	int items = 0;  	bool moreItems = false;  	LLSD events_to_save = events; -	if (!events.emptyMap()) +	if (events.isMap() && events.size() != 0)  	{  		LLSD::map_const_iterator day = events.endMap();  		do diff --git a/indra/newview/llpanellandmedia.cpp b/indra/newview/llpanellandmedia.cpp index 26cd3ff1c1..e379d67e37 100644 --- a/indra/newview/llpanellandmedia.cpp +++ b/indra/newview/llpanellandmedia.cpp @@ -179,7 +179,6 @@ void LLPanelLandMedia::refresh()  		// enable/disable for text label for completeness  		mMediaSizeCtrlLabel->setEnabled( can_change_media && allow_resize ); -		LLUUID tmp = parcel->getMediaID();  		mMediaTextureCtrl->setImageAssetID ( parcel->getMediaID() );  		mMediaTextureCtrl->setEnabled( can_change_media ); diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 9df3a8e31a..b14fdbf38e 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -1103,6 +1103,18 @@ void LLPanelLogin::onRememberPasswordCheck(void*)      if (sInstance)      {          gSavedSettings.setBOOL("UpdateRememberPasswordSetting", TRUE); + +        LLPointer<LLCredential> cred; +        bool remember_user, remember_password; +        getFields(cred, remember_user, remember_password); + +        std::string grid(LLGridManager::getInstance()->getGridId()); +        std::string user_id(cred->userID()); +        if (!remember_password) +        { +            gSecAPIHandler->removeFromProtectedMap("mfa_hash", grid, user_id); +            gSecAPIHandler->syncProtectedMap(); +        }      }  } diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 89256b40c4..744d49ff57 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -307,6 +307,13 @@ LLPanelMainInventory::~LLPanelMainInventory( void )  	gInventory.removeObserver(this);  	delete mSavedFolderState; + +	auto menu = mMenuAddHandle.get(); +	if(menu) +	{ +		menu->die(); +		mMenuAddHandle.markDead(); +	}  }  LLInventoryPanel* LLPanelMainInventory::getAllItemsPanel() @@ -403,6 +410,18 @@ void LLPanelMainInventory::resetFilters()  	setFilterTextFromFilter();  } +void LLPanelMainInventory::resetAllItemsFilters() +{ +    LLFloaterInventoryFinder *finder = getFinder(); +    getAllItemsPanel()->getFilter().resetDefault(); +    if (finder) +    { +        finder->updateElementsFromFilter(); +    } + +    setFilterTextFromFilter(); +} +  void LLPanelMainInventory::setSortBy(const LLSD& userdata)  {  	U32 sort_order_mask = getActivePanel()->getSortOrder(); @@ -1177,13 +1196,12 @@ void LLPanelMainInventory::initListCommandsHandlers()  	mEnableCallbackRegistrar.add("Inventory.GearDefault.Check", boost::bind(&LLPanelMainInventory::isActionChecked, this, _2));  	mEnableCallbackRegistrar.add("Inventory.GearDefault.Enable", boost::bind(&LLPanelMainInventory::isActionEnabled, this, _2));  	mMenuGearDefault = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_inventory_gear_default.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); -	mGearMenuButton->setMenu(mMenuGearDefault); +	mGearMenuButton->setMenu(mMenuGearDefault, LLMenuButton::MP_TOP_LEFT, true);  	LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_inventory_add.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());  	mMenuAddHandle = menu->getHandle();  	mMenuVisibility = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>("menu_inventory_search_visibility.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); -	mVisibilityMenuButton->setMenu(mMenuVisibility); -	mVisibilityMenuButton->setMenuPosition(LLMenuButton::MP_BOTTOM_LEFT); +	mVisibilityMenuButton->setMenu(mMenuVisibility, LLMenuButton::MP_BOTTOM_LEFT, true);  	// Update the trash button when selected item(s) get worn or taken off.  	LLOutfitObserver::instance().addCOFChangedCallback(boost::bind(&LLPanelMainInventory::updateListCommands, this)); diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h index 257bce930c..7aae5a0b3c 100644 --- a/indra/newview/llpanelmaininventory.h +++ b/indra/newview/llpanelmaininventory.h @@ -96,6 +96,7 @@ public:  	void toggleFindOptions();      void resetFilters(); +    void resetAllItemsFilters();  protected:  	// diff --git a/indra/newview/llpanelmediasettingsgeneral.cpp b/indra/newview/llpanelmediasettingsgeneral.cpp index 416857bd30..8380394f2c 100644 --- a/indra/newview/llpanelmediasettingsgeneral.cpp +++ b/indra/newview/llpanelmediasettingsgeneral.cpp @@ -39,6 +39,7 @@  #include "llagent.h"  #include "llviewerwindow.h"  #include "llviewermedia.h" +#include "llvovolume.h"  #include "llsdutil.h"  #include "llselectmgr.h"  #include "llbutton.h" @@ -452,10 +453,17 @@ bool LLPanelMediaSettingsGeneral::navigateHomeSelectedFace(bool only_if_current_  					{  						viewer_media_t media_impl =  							LLViewerMedia::getInstance()->getMediaImplFromTextureID(object->getTE(face)->getMediaData()->getMediaID()); -						if(media_impl) -						{ +                        if (media_impl) +                        {                              media_impl->setPriority(LLPluginClassMedia::PRIORITY_NORMAL);                              media_impl->navigateHome(); + +                            if (!only_if_current_is_empty) +                            { +                                LLSD media_data; +                                media_data[LLMediaEntry::CURRENT_URL_KEY] = std::string(); +                                object->getTE(face)->mergeIntoMediaData(media_data); +                            }  							return true;  						}  					} @@ -471,6 +479,23 @@ bool LLPanelMediaSettingsGeneral::navigateHomeSelectedFace(bool only_if_current_  	LLObjectSelectionHandle selected_objects =LLSelectMgr::getInstance()->getSelection();  	selected_objects->getSelectedTEValue( &functor_navigate_media, all_face_media_navigated ); +    if (all_face_media_navigated) +    { +        struct functor_sync_to_server : public LLSelectedObjectFunctor +        { +            virtual bool apply(LLViewerObject* object) +            { +                LLVOVolume *volume = dynamic_cast<LLVOVolume*>(object); +                if (volume) +                { +                    volume->sendMediaDataUpdate(); +                } +                return true; +            } +        } sendfunc; +        selected_objects->applyToObjects(&sendfunc); +    } +  	// Note: we don't update the 'current URL' field until the media data itself changes  	return all_face_media_navigated; diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index bc7933d84b..2da431955f 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -2131,7 +2131,7 @@ bool LLPanelObject::menuEnableItem(const LLSD& userdata)      }      else if (command == "params_paste")      { -        return mClipboardParams.isMap() && !mClipboardParams.emptyMap(); +        return mClipboardParams.isMap() && (mClipboardParams.size() != 0);      }      // copy options      else if (command == "psr_copy") diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index fff25c6c61..bd40c9dd2b 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -1275,7 +1275,8 @@ LLPanelObjectInventory::LLPanelObjectInventory(const LLPanelObjectInventory::Par  	mHaveInventory(FALSE),  	mIsInventoryEmpty(TRUE),  	mInventoryNeedsUpdate(FALSE), -	mInventoryViewModel(p.name) +	mInventoryViewModel(p.name), +    mShowRootFolder(p.show_root_folder)  {  	// Setup context menu callbacks  	mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLPanelObjectInventory::doToSelected, this, _2)); @@ -1360,6 +1361,7 @@ void LLPanelObjectInventory::reset()  	mFolders = LLUICtrlFactory::create<LLFolderView>(p);  	mFolders->setCallbackRegistrar(&mCommitCallbackRegistrar); +	mFolders->setEnableRegistrar(&mEnableCallbackRegistrar);  	if (hasFocus())  	{ @@ -1526,15 +1528,23 @@ void LLPanelObjectInventory::createFolderViews(LLInventoryObject* inventory_root  		p.font_highlight_color = item_color;  		LLFolderViewFolder* new_folder = LLUICtrlFactory::create<LLFolderViewFolder>(p); -		new_folder->addToFolder(mFolders); -		new_folder->toggleOpen(); + +        if (mShowRootFolder) +        { +            new_folder->addToFolder(mFolders); +            new_folder->toggleOpen(); +        }  		if (!contents.empty())  		{ -			createViewsForCategory(&contents, inventory_root, new_folder); +			createViewsForCategory(&contents, inventory_root, mShowRootFolder ? new_folder : mFolders);  		} -        // Refresh for label to add item count -        new_folder->refresh(); + +        if (mShowRootFolder) +        { +            // Refresh for label to add item count +            new_folder->refresh(); +        }  	}  } diff --git a/indra/newview/llpanelobjectinventory.h b/indra/newview/llpanelobjectinventory.h index 7b9ecfb8f3..0e450d8ce9 100644 --- a/indra/newview/llpanelobjectinventory.h +++ b/indra/newview/llpanelobjectinventory.h @@ -48,8 +48,14 @@ class LLViewerObject;  class LLPanelObjectInventory : public LLPanel, public LLVOInventoryListener  {  public: -	// dummy param block for template registration purposes -	struct Params : public LLPanel::Params {}; +    struct Params : public LLInitParam::Block<Params, LLPanel::Params> +    { +        Optional<bool> show_root_folder; + +        Params() +            : show_root_folder("show_root_folder", true) +        {} +    };  	LLPanelObjectInventory(const Params&);  	virtual ~LLPanelObjectInventory(); @@ -110,6 +116,7 @@ private:  	BOOL mIsInventoryEmpty; // 'Empty' label  	BOOL mInventoryNeedsUpdate; // for idle, set on changed callback  	LLFolderViewModelInventory	mInventoryViewModel;	 +    bool mShowRootFolder;  };  #endif // LL_LLPANELOBJECTINVENTORY_H diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 74ec576554..0f00231643 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -800,7 +800,6 @@ void LLPanelPlaces::onSaveButtonClicked()  	LLStringUtil::trim(current_title_value);  	LLStringUtil::trim(current_notes_value); -	LLUUID item_id = mItem->getUUID();  	LLUUID folder_id = mLandmarkInfo->getLandmarkFolder();  	bool change_parent = folder_id != mItem->getParentUUID(); diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index f4eaa78f11..708ff26ced 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -484,6 +484,30 @@ public:  	// requires trusted browser to trigger  	LLAgentHandler() : LLCommandHandler("agent", UNTRUSTED_THROTTLE) { } +    virtual bool canHandleUntrusted( +        const LLSD& params, +        const LLSD& query_map, +        LLMediaCtrl* web, +        const std::string& nav_type) +    { +        if (params.size() < 2) +        { +            return true; // don't block, will fail later +        } + +        if (nav_type == NAV_TYPE_CLICKED) +        { +            return true; +        } + +        const std::string verb = params[1].asString(); +        if (verb == "about" || verb == "inspect" || verb == "reportAbuse") +        { +            return true; +        } +        return false; +    } +  	bool handle(const LLSD& params, const LLSD& query_map,  		LLMediaCtrl* web)  	{ @@ -1031,7 +1055,6 @@ void LLPanelProfileSecondLife::resetData()  void LLPanelProfileSecondLife::processProfileProperties(const LLAvatarData* avatar_data)  { -    LLUUID avatar_id = getAvatarId();      const LLRelationship* relationship = LLAvatarTracker::instance().getBuddyInfo(getAvatarId());      if ((relationship != NULL || gAgent.isGodlike()) && !getSelfProfile())      { @@ -1280,6 +1303,8 @@ void LLPanelProfileSecondLife::fillRightsData()  void LLPanelProfileSecondLife::fillAgeData(const LLDate &born_on)  { +    // Date from server comes already converted to stl timezone, +    // so display it as an UTC + 0      std::string name_and_date = getString("date_format");      LLSD args_name;      args_name["datetime"] = (S32)born_on.secondsSinceEpoch(); diff --git a/indra/newview/llpanelprofileclassifieds.cpp b/indra/newview/llpanelprofileclassifieds.cpp index a3913ddc49..1ff12b4f37 100644 --- a/indra/newview/llpanelprofileclassifieds.cpp +++ b/indra/newview/llpanelprofileclassifieds.cpp @@ -81,6 +81,30 @@ public:  	std::set<LLUUID> mClassifiedIds;  	std::string mRequestVerb; + +    virtual bool canHandleUntrusted( +        const LLSD& params, +        const LLSD& query_map, +        LLMediaCtrl* web, +        const std::string& nav_type) +    { +        if (params.size() < 1) +        { +            return true; // don't block, will fail later +        } + +        if (nav_type == NAV_TYPE_CLICKED) +        { +            return true; +        } + +        const std::string verb = params[0].asString(); +        if (verb == "create") +        { +            return false; +        } +        return true; +    }  	bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)      { diff --git a/indra/newview/llpanelprofilepicks.cpp b/indra/newview/llpanelprofilepicks.cpp index 774119f169..45d0252e4f 100644 --- a/indra/newview/llpanelprofilepicks.cpp +++ b/indra/newview/llpanelprofilepicks.cpp @@ -63,6 +63,30 @@ public:      // requires trusted browser to trigger      LLPickHandler() : LLCommandHandler("pick", UNTRUSTED_THROTTLE) { } +    virtual bool canHandleUntrusted( +        const LLSD& params, +        const LLSD& query_map, +        LLMediaCtrl* web, +        const std::string& nav_type) +    { +        if (params.size() < 1) +        { +            return true; // don't block, will fail later +        } + +        if (nav_type == NAV_TYPE_CLICKED) +        { +            return true; +        } + +        const std::string verb = params[0].asString(); +        if (verb == "create") +        { +            return false; +        } +        return true; +    } +      bool handle(const LLSD& params, const LLSD& query_map,          LLMediaCtrl* web)      { diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index 3fd4f51559..33656566d1 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -255,7 +255,7 @@ void LLPreviewNotecard::loadAsset()  			else  			{  				LLHost source_sim = LLHost(); -				LLSD* user_data = new LLSD(); +				LLSD* user_data = nullptr;  				if (mObjectUUID.notNull())  				{  					LLViewerObject *objectp = gObjectList.findObject(mObjectUUID); @@ -274,6 +274,7 @@ void LLPreviewNotecard::loadAsset()  						mAssetStatus = PREVIEW_ASSET_LOADED;  						return;  					} +					user_data = new LLSD();  					user_data->with("taskid", mObjectUUID).with("itemid", mItemUUID);  				}  				else diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp index 2e44dc1459..7089df677e 100644 --- a/indra/newview/llscenemonitor.cpp +++ b/indra/newview/llscenemonitor.cpp @@ -515,7 +515,7 @@ void LLSceneMonitor::fetchQueryResult()  }  //dump results to a file _scene_xmonitor_results.csv -void LLSceneMonitor::dumpToFile(std::string file_name) +void LLSceneMonitor::dumpToFile(const std::string &file_name)  {  	if (!hasResults()) return; diff --git a/indra/newview/llscenemonitor.h b/indra/newview/llscenemonitor.h index 7cd531bd34..f2e1ef69b9 100644 --- a/indra/newview/llscenemonitor.h +++ b/indra/newview/llscenemonitor.h @@ -61,7 +61,7 @@ public:  	bool needsUpdate() const;  	const LLTrace::ExtendablePeriodicRecording* getRecording() const {return &mSceneLoadRecording;} -	void dumpToFile(std::string file_name); +	void dumpToFile(const std::string &file_name);  	bool hasResults() const { return mSceneLoadRecording.getResults().getDuration() != S32Seconds(0);}  	void reset(); diff --git a/indra/newview/llscriptfloater.cpp b/indra/newview/llscriptfloater.cpp index da912ef3d4..6a27ff3047 100644 --- a/indra/newview/llscriptfloater.cpp +++ b/indra/newview/llscriptfloater.cpp @@ -460,10 +460,11 @@ void LLScriptFloaterManager::onAddNotification(const LLUUID& notification_id)  		if(it != mNotifications.end())  		{ +			LLUUID old_id = it->first; // copy LLUUID to prevent use after free when it is erased below  			LLChicletPanel * chiclet_panelp = LLChicletBar::getInstance()->getChicletPanel();  			if (NULL != chiclet_panelp)  			{ -				LLIMChiclet * chicletp = chiclet_panelp->findChiclet<LLIMChiclet>(it->first); +				LLIMChiclet * chicletp = chiclet_panelp->findChiclet<LLIMChiclet>(old_id);  				if (NULL != chicletp)  				{  					// Pass the new_message icon state further. @@ -472,14 +473,14 @@ void LLScriptFloaterManager::onAddNotification(const LLUUID& notification_id)  				}  			} -			LLScriptFloater* floater = LLFloaterReg::findTypedInstance<LLScriptFloater>("script_floater", it->first); +			LLScriptFloater* floater = LLFloaterReg::findTypedInstance<LLScriptFloater>("script_floater", old_id);  			if (floater)  			{  				// Generate chiclet with a "new message" indicator if a docked window was opened but not in focus. See EXT-3142.  				set_new_message |= !floater->hasFocus();  			} -			removeNotification(it->first); +			removeNotification(old_id);  		}  	} diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp index 7c762170a7..707b602fc6 100644 --- a/indra/newview/llsettingsvo.cpp +++ b/indra/newview/llsettingsvo.cpp @@ -694,8 +694,8 @@ void LLSettingsVOSky::applySpecial(void *ptarget, bool force)          LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); -        LLVector4 sunDiffuse = LLVector4(psky->getSunlightColor().mV); -        LLVector4 moonDiffuse = LLVector4(psky->getMoonlightColor().mV); +        LLVector4 sunDiffuse = LLVector4(LLVector3(psky->getSunlightColor().mV)); +        LLVector4 moonDiffuse = LLVector4(LLVector3(psky->getMoonlightColor().mV));          shader->uniform4fv(LLShaderMgr::SUNLIGHT_COLOR, sunDiffuse);          shader->uniform4fv(LLShaderMgr::MOONLIGHT_COLOR, moonDiffuse); diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index ea671a130e..60bada8f58 100644 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -982,7 +982,6 @@ void LLActiveSpeakerMgr::updateSpeakerList()  	// clean up text only speakers  	for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it)  	{ -		LLUUID speaker_id = speaker_it->first;  		LLSpeaker* speakerp = speaker_it->second;  		if (speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY)  		{ diff --git a/indra/newview/llspeakingindicatormanager.cpp b/indra/newview/llspeakingindicatormanager.cpp index 5ca1d4b4a5..0111d8869c 100644 --- a/indra/newview/llspeakingindicatormanager.cpp +++ b/indra/newview/llspeakingindicatormanager.cpp @@ -51,6 +51,10 @@ class SpeakingIndicatorManager : public LLSingleton<SpeakingIndicatorManager>, L  	LLSINGLETON(SpeakingIndicatorManager);  	~SpeakingIndicatorManager();  	LOG_CLASS(SpeakingIndicatorManager); + +protected: +    void                cleanupSingleton(); +  public:  	/** @@ -183,12 +187,16 @@ SpeakingIndicatorManager::SpeakingIndicatorManager()  SpeakingIndicatorManager::~SpeakingIndicatorManager()  { -	// Don't use LLVoiceClient::getInstance() here without check -	// singleton MAY have already been destroyed. -	if(LLVoiceClient::instanceExists()) -	{ -		LLVoiceClient::getInstance()->removeObserver(this); -	} +} + +void SpeakingIndicatorManager::cleanupSingleton() +{ +    // Don't use LLVoiceClient::getInstance() here without a check, +    // singleton MAY have already been destroyed. +    if (LLVoiceClient::instanceExists()) +    { +        LLVoiceClient::getInstance()->removeObserver(this); +    }  }  void SpeakingIndicatorManager::sOnCurrentChannelChanged(const LLUUID& /*session_id*/) diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 1dd5c5cbe5..6883ead5ee 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -272,12 +272,10 @@ void show_first_run_dialog();  bool first_run_dialog_callback(const LLSD& notification, const LLSD& response);  void set_startup_status(const F32 frac, const std::string& string, const std::string& msg);  bool login_alert_status(const LLSD& notification, const LLSD& response); -void login_packet_failed(void**, S32 result);  void use_circuit_callback(void**, S32 result);  void register_viewer_callbacks(LLMessageSystem* msg);  void asset_callback_nothing(const LLUUID&, LLAssetType::EType, void*, S32);  bool callback_choose_gender(const LLSD& notification, const LLSD& response); -void init_start_screen(S32 location_id);  void release_start_screen();  void reset_login();  LLSD transform_cert_args(LLPointer<LLCertificate> cert); diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp index 024f25bc98..bf3f4c1e88 100644 --- a/indra/newview/lltoastnotifypanel.cpp +++ b/indra/newview/lltoastnotifypanel.cpp @@ -89,6 +89,7 @@ LLButton* LLToastNotifyPanel::createButton(const LLSD& form_element, BOOL is_opt  	const LLFontGL* font = make_small_btn ? sFontSmall: sFont; // for block and ignore buttons in script dialog  	p.name = form_element["name"].asString();  	p.label = form_element["text"].asString(); +	p.tool_tip = form_element["text"].asString();  	p.font = font;  	p.rect.height = BTN_HEIGHT;  	p.click_callback.function(boost::bind(&LLToastNotifyPanel::onClickButton, userdata)); diff --git a/indra/newview/lltoolbarview.cpp b/indra/newview/lltoolbarview.cpp index 752fc6f3f3..01d799dcd5 100644 --- a/indra/newview/lltoolbarview.cpp +++ b/indra/newview/lltoolbarview.cpp @@ -44,7 +44,6 @@  #include "llagent.h"  // HACK for destinations guide on startup  #include "llfloaterreg.h"  // HACK for destinations guide on startup  #include "llviewercontrol.h"  // HACK for destinations guide on startup -#include "llinventorymodel.h" // HACK to disable starter avatars button for NUX  #include <boost/foreach.hpp> @@ -320,22 +319,6 @@ bool LLToolBarView::loadToolbars(bool force_default)  			}  		}  	} - -    // SL-18581: Don't show the starter avatar toolbar button for NUX users -    LLViewerInventoryCategory* my_outfits_cat = gInventory.getCategory(gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS)); -    if (gAgent.isFirstLogin() -        && my_outfits_cat != NULL -        && my_outfits_cat->getDescendentCount() > 0) -    { -        for (S32 i = LLToolBarEnums::TOOLBAR_FIRST; i <= LLToolBarEnums::TOOLBAR_LAST; i++) -        { -            if (mToolbars[i]) -            { -                mToolbars[i]->removeCommand(LLCommandId("avatar")); -            } -        } -    } -  	mToolbarsLoaded = true;  	return true;  } diff --git a/indra/newview/lltoolfocus.cpp b/indra/newview/lltoolfocus.cpp index 07f46c5fbe..4e94895a3e 100644 --- a/indra/newview/lltoolfocus.cpp +++ b/indra/newview/lltoolfocus.cpp @@ -75,6 +75,7 @@ LLToolCamera::LLToolCamera()  	mOutsideSlopX(FALSE),  	mOutsideSlopY(FALSE),  	mValidClickPoint(FALSE), +    mClickPickPending(false),  	mValidSelection(FALSE),  	mMouseSteering(FALSE),  	mMouseUpX(0), @@ -127,6 +128,11 @@ BOOL LLToolCamera::handleMouseDown(S32 x, S32 y, MASK mask)  	mValidClickPoint = FALSE; +    // Sometimes Windows issues down and up events near simultaneously +    // without giving async pick a chance to trigged +    // Ex: mouse from numlock emulation +    mClickPickPending = true; +  	// If mouse capture gets ripped away, claim we moused up  	// at the point we moused down. JC  	mMouseUpX = x; @@ -142,13 +148,15 @@ BOOL LLToolCamera::handleMouseDown(S32 x, S32 y, MASK mask)  void LLToolCamera::pickCallback(const LLPickInfo& pick_info)  { -	if (!LLToolCamera::getInstance()->hasMouseCapture()) +    LLToolCamera* camera = LLToolCamera::getInstance(); +	if (!camera->mClickPickPending)  	{  		return;  	} +    camera->mClickPickPending = false; -	LLToolCamera::getInstance()->mMouseDownX = pick_info.mMousePt.mX; -	LLToolCamera::getInstance()->mMouseDownY = pick_info.mMousePt.mY; +    camera->mMouseDownX = pick_info.mMousePt.mX; +    camera->mMouseDownY = pick_info.mMousePt.mY;  	gViewerWindow->moveCursorToCenter(); @@ -158,7 +166,7 @@ void LLToolCamera::pickCallback(const LLPickInfo& pick_info)  	// Check for hit the sky, or some other invalid point  	if (!hit_obj && pick_info.mPosGlobal.isExactlyZero())  	{ -		LLToolCamera::getInstance()->mValidClickPoint = FALSE; +        camera->mValidClickPoint = FALSE;  		return;  	} @@ -168,7 +176,7 @@ void LLToolCamera::pickCallback(const LLPickInfo& pick_info)  		LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();  		if (!selection->getObjectCount() || selection->getSelectType() != SELECT_TYPE_HUD)  		{ -			LLToolCamera::getInstance()->mValidClickPoint = FALSE; +            camera->mValidClickPoint = FALSE;  			return;  		}  	} @@ -192,7 +200,7 @@ void LLToolCamera::pickCallback(const LLPickInfo& pick_info)  		if( !good_customize_avatar_hit )  		{ -			LLToolCamera::getInstance()->mValidClickPoint = FALSE; +            camera->mValidClickPoint = FALSE;  			return;  		} @@ -237,7 +245,7 @@ void LLToolCamera::pickCallback(const LLPickInfo& pick_info)  	} -	LLToolCamera::getInstance()->mValidClickPoint = TRUE; +    camera->mValidClickPoint = TRUE;  	if( CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode() )  	{ @@ -284,32 +292,36 @@ BOOL LLToolCamera::handleMouseUp(S32 x, S32 y, MASK mask)  	if (hasMouseCapture())  	{ -		if (mValidClickPoint) -		{ -			if( CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode() ) -			{ -				LLCoordGL mouse_pos; -				LLVector3 focus_pos = gAgent.getPosAgentFromGlobal(gAgentCamera.getFocusGlobal()); -				BOOL success = LLViewerCamera::getInstance()->projectPosAgentToScreen(focus_pos, mouse_pos); -				if (success) -				{ -					LLUI::getInstance()->setMousePositionScreen(mouse_pos.mX, mouse_pos.mY); -				} -			} -			else if (mMouseSteering) -			{ -				LLUI::getInstance()->setMousePositionScreen(mMouseDownX, mMouseDownY); -			} -			else -			{ -				gViewerWindow->moveCursorToCenter(); -			} -		} -		else -		{ -			// not a valid zoomable object -			LLUI::getInstance()->setMousePositionScreen(mMouseDownX, mMouseDownY); -		} +        // Do not move camera if we haven't gotten a pick +        if (!mClickPickPending) +        { +            if (mValidClickPoint) +            { +                if (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode()) +                { +                    LLCoordGL mouse_pos; +                    LLVector3 focus_pos = gAgent.getPosAgentFromGlobal(gAgentCamera.getFocusGlobal()); +                    BOOL success = LLViewerCamera::getInstance()->projectPosAgentToScreen(focus_pos, mouse_pos); +                    if (success) +                    { +                        LLUI::getInstance()->setMousePositionScreen(mouse_pos.mX, mouse_pos.mY); +                    } +                } +                else if (mMouseSteering) +                { +                    LLUI::getInstance()->setMousePositionScreen(mMouseDownX, mMouseDownY); +                } +                else +                { +                    gViewerWindow->moveCursorToCenter(); +                } +            } +            else +            { +                // not a valid zoomable object +                LLUI::getInstance()->setMousePositionScreen(mMouseDownX, mMouseDownY); +            } +        }  		// calls releaseMouse() internally  		setMouseCapture(FALSE); diff --git a/indra/newview/lltoolfocus.h b/indra/newview/lltoolfocus.h index cfc235b6c2..ef71f9230a 100644 --- a/indra/newview/lltoolfocus.h +++ b/indra/newview/lltoolfocus.h @@ -49,6 +49,7 @@ public:  	virtual LLTool*	getOverrideTool(MASK mask) { return NULL; } +    void setClickPickPending() { mClickPickPending = true; }  	static void pickCallback(const LLPickInfo& pick_info);  	BOOL mouseSteerMode() { return mMouseSteering; } @@ -65,6 +66,7 @@ protected:  	BOOL	mOutsideSlopX;  	BOOL	mOutsideSlopY;  	BOOL	mValidClickPoint; +    bool	mClickPickPending;  	BOOL	mValidSelection;  	BOOL	mMouseSteering;  	S32		mMouseUpX;	// needed for releaseMouse() diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 5fb83bf08e..58011bbde2 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -443,6 +443,7 @@ BOOL LLToolPie::handleLeftClickPick()  		LLToolMgr::getInstance()->setTransientTool(LLToolCamera::getInstance());  		gViewerWindow->hideCursor();  		LLToolCamera::getInstance()->setMouseCapture(TRUE); +        LLToolCamera::getInstance()->setClickPickPending();  		LLToolCamera::getInstance()->pickCallback(mPick);  		gAgentCamera.setFocusOnAvatar(TRUE, TRUE); diff --git a/indra/newview/llurldispatcher.cpp b/indra/newview/llurldispatcher.cpp index a1670351f4..7c92e7ef98 100644 --- a/indra/newview/llurldispatcher.cpp +++ b/indra/newview/llurldispatcher.cpp @@ -263,7 +263,7 @@ public:  	// inside the app, otherwise a malicious web page could  	// cause a constant teleport loop.  JC  	LLTeleportHandler() : -		LLCommandHandler("teleport", UNTRUSTED_THROTTLE), +		LLCommandHandler("teleport", UNTRUSTED_CLICK_ONLY),  		LLEventAPI("LLTeleportHandler", "Low-level teleport API")  	{  		LLEventAPI::add("teleport", diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp index 232b52a3f9..13491114b9 100644 --- a/indra/newview/llviewerassetupload.cpp +++ b/indra/newview/llviewerassetupload.cpp @@ -704,7 +704,7 @@ LLUUID LLBufferedAssetUploadInfo::finishUpload(LLSD &result)  LLScriptAssetUpload::LLScriptAssetUpload(LLUUID itemId, std::string buffer, invnUploadFinish_f finish):      LLBufferedAssetUploadInfo(itemId, LLAssetType::AT_LSL_TEXT, buffer, finish),      mExerienceId(), -    mTargetType(LSL2), +    mTargetType(MONO),      mIsRunning(false)  {  } @@ -725,7 +725,7 @@ LLSD LLScriptAssetUpload::generatePostBody()      if (getTaskId().isNull())      {          body["item_id"] = getItemId(); -        body["target"] = "lsl2"; +        body["target"] = "mono";      }      else      { diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 59654350e4..c0398372b4 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -174,11 +174,103 @@ const std::string FLOATER_PROFILE("profile");  class LLFloaterOpenHandler : public LLCommandHandler  {  public: -	// requires trusted browser to trigger +	// requires trusted browser to trigger or an explicit click  	LLFloaterOpenHandler() : LLCommandHandler("openfloater", UNTRUSTED_THROTTLE) { } -	bool handle(const LLSD& params, const LLSD& query_map, -				LLMediaCtrl* web) +    bool canHandleUntrusted( +        const LLSD& params, +        const LLSD& query_map, +        LLMediaCtrl* web, +        const std::string& nav_type) override +    { +        if (params.size() != 1) +        { +            return true; // will fail silently +        } +         +        std::string fl_name = params[0].asString(); + +        if (nav_type == NAV_TYPE_CLICKED) +        { +            const std::list<std::string> blacklist_clicked = { +                "camera_presets", +                "delete_pref_preset", +                "forget_username", +                "god_tools", +                "group_picker", +                "hud", +                "incoming_call", +                "linkreplace", +                "message_critical", // Modal!!! Login specific. +                "message_tos", // Modal!!! Login specific. +                "save_pref_preset", +                "save_camera_preset", +                "region_restarting", +                "outfit_snapshot", +                "upload_anim_bvh", +                "upload_anim_anim", +                "upload_image", +                "upload_model", +                "upload_script", +                "upload_sound" +            }; +            return std::find(blacklist_clicked.begin(), blacklist_clicked.end(), fl_name) == blacklist_clicked.end(); +        } +        else +        { +            const std::list<std::string> blacklist_untrusted = { +                "360capture", +                "block_timers", +                "add_payment_method", +                "appearance", +                "associate_listing", +                "avatar_picker", +                "camera", +                "camera_presets", +                "classified", +                "add_landmark", +                "delete_pref_preset", +                "env_fixed_environmentent_water", +                "env_fixed_environmentent_sky", +                "env_edit_extdaycycle", +                "font_test", +                "forget_username", +                "god_tools", +                "group_picker", +                "hud", +                "incoming_call", +                "linkreplace", +                "mem_leaking", +                "marketplace_validation", +                "message_critical", // Modal!!! Login specific. If this is in use elsewhere, better to create a non modal variant +                "message_tos", // Modal!!! Login specific. +                "mute_object_by_name", +                "publish_classified", +                "save_pref_preset", +                "save_camera_preset", +                "region_restarting", +                "script_debug", +                "script_debug_output", +                "sell_land", +                "outfit_snapshot", +                "upload_anim_bvh", +                "upload_anim_anim", +                "upload_image", +                "upload_model", +                "upload_script", +                "upload_sound" +            }; +            return std::find(blacklist_untrusted.begin(), blacklist_untrusted.end(), fl_name) == blacklist_untrusted.end(); +        } + + +        return true; +    } + +	bool handle( +        const LLSD& params, +        const LLSD& query_map, +        LLMediaCtrl* web) override  	{  		if (params.size() != 1)  		{ diff --git a/indra/newview/llviewerinput.cpp b/indra/newview/llviewerinput.cpp index 43b9cd90bd..6bab2c2100 100644 --- a/indra/newview/llviewerinput.cpp +++ b/indra/newview/llviewerinput.cpp @@ -1614,12 +1614,22 @@ BOOL LLViewerInput::handleMouse(LLWindow *window_impl, LLCoordGL pos, MASK mask,              clicktype = CLICK_DOUBLELEFT;          } +        // If the first LMB click is handled by the menu, skip the following double click +        static bool skip_double_click = false; +        if (clicktype == CLICK_LEFT && down ) +        { +            skip_double_click = handled; +        }          if (double_click_sp && down)          {              // Consume click.              // Due to handling, double click that is not handled will be immediately followed by LMB click          } +        else if (clicktype == CLICK_DOUBLELEFT && skip_double_click) +        { +            handled = true; +        }          // If UI handled 'down', it should handle 'up' as well          // If we handle 'down' not by UI, then we should handle 'up'/'level' regardless of UI          else if (handled) diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 55ac817479..50252556de 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -232,7 +232,7 @@ class LLInventoryHandler : public LLCommandHandler  {  public:  	// requires trusted browser to trigger -	LLInventoryHandler() : LLCommandHandler("inventory", UNTRUSTED_THROTTLE) { } +	LLInventoryHandler() : LLCommandHandler("inventory", UNTRUSTED_CLICK_ONLY) { }  	bool handle(const LLSD& params, const LLSD& query_map,  				LLMediaCtrl* web) diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index c796ed30f7..a0223a5dbb 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -2803,14 +2803,15 @@ void handle_object_show_original()  } -static void init_default_item_label(const std::string& item_name) +static void init_default_item_label(LLUICtrl* ctrl)  { +	const std::string& item_name = ctrl->getName();  	boost::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name);  	if (it == sDefaultItemLabels.end())  	{  		// *NOTE: This will not work for items of type LLMenuItemCheckGL because they return boolean value  		//       (doesn't seem to matter much ATM). -		LLStringExplicit default_label = gMenuHolder->childGetValue(item_name).asString(); +		LLStringExplicit default_label = ctrl->getValue().asString();  		if (!default_label.empty())  		{  			sDefaultItemLabels.insert(std::pair<std::string, LLStringExplicit>(item_name, default_label)); @@ -2841,18 +2842,17 @@ bool enable_object_touch(LLUICtrl* ctrl)  		new_value = obj->flagHandleTouch() || (parent && parent->flagHandleTouch());  	} -	std::string item_name = ctrl->getName(); -	init_default_item_label(item_name); +	init_default_item_label(ctrl);  	// Update label based on the node touch name if available.  	LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();  	if (node && node->mValid && !node->mTouchName.empty())  	{ -		gMenuHolder->childSetValue(item_name, node->mTouchName); +		ctrl->setValue(node->mTouchName);  	}  	else  	{ -		gMenuHolder->childSetValue(item_name, get_default_item_label(item_name)); +		ctrl->setValue(get_default_item_label(ctrl->getName()));  	}  	return new_value; @@ -5632,6 +5632,7 @@ class LLToolsSelectNextPartFace : public view_listener_t                      }                  }                  LLSelectMgr::getInstance()->selectObjectOnly(to_select, new_te); +                LLSelectMgr::getInstance()->addAsIndividual(to_select, new_te, false);              }              else              { @@ -6595,20 +6596,18 @@ bool enable_object_sit(LLUICtrl* ctrl)  	bool sitting_on_sel = sitting_on_selection();  	if (!sitting_on_sel)  	{ -		std::string item_name = ctrl->getName(); -  		// init default labels -		init_default_item_label(item_name); +		init_default_item_label(ctrl);  		// Update label  		LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();  		if (node && node->mValid && !node->mSitName.empty())  		{ -			gMenuHolder->childSetValue(item_name, node->mSitName); +			ctrl->setValue(node->mSitName);  		}  		else  		{ -			gMenuHolder->childSetValue(item_name, get_default_item_label(item_name)); +			ctrl->setValue(get_default_item_label(ctrl->getName()));  		}  	}  	return !sitting_on_sel && is_object_sittable(); @@ -7654,7 +7653,6 @@ void handle_selected_texture_info(void*)     		map_t::iterator it;     		for (it = faces_per_texture.begin(); it != faces_per_texture.end(); ++it)     		{ -   			LLUUID image_id = it->first;     			U8 te = it->second[0];     			LLViewerTexture* img = node->getObject()->getTEImage(te);     			S32 height = img->getHeight(); diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index d97ed61e11..17d4f1928c 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1907,7 +1907,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&  				log_message = LLTrans::getString("InvOfferDecline", log_message_args);  			}  			chat.mText = log_message; -			if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::getInstance()->isLinden(mFromName) )  // muting for SL-42269 +			if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::isLinden(mFromName) )  // muting for SL-42269  			{  				chat.mMuted = TRUE;  				accept_to_trash = false; // will send decline message @@ -2512,7 +2512,7 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data)  		LLMute::flagTextChat)   		|| LLMuteList::getInstance()->isMuted(owner_id, LLMute::flagTextChat);  	is_linden = chat.mSourceType != CHAT_SOURCE_OBJECT && -		LLMuteList::getInstance()->isLinden(from_name); +		LLMuteList::isLinden(from_name);  	if (is_muted && (chat.mSourceType == CHAT_SOURCE_OBJECT))  	{ @@ -5819,8 +5819,12 @@ void process_script_question(LLMessageSystem *msg, void **user_data)  			{  				count++;  				known_questions |= script_perm.permbit; -				// check whether permission question should cause special caution dialog -				caution |= (script_perm.caution); + +                if (!LLMuteList::isLinden(owner_name)) +                { +                    // check whether permission question should cause special caution dialog +                    caution |= (script_perm.caution); +                }  				if (("ScriptTakeMoney" == script_perm.question) && has_not_only_debit)  					continue; @@ -6346,7 +6350,7 @@ bool teleport_request_callback(const LLSD& notification, const LLSD& response)  	LLAvatarName av_name;  	LLAvatarNameCache::get(from_id, &av_name); -	if(LLMuteList::getInstance()->isMuted(from_id) && !LLMuteList::getInstance()->isLinden(av_name.getUserName())) +	if(LLMuteList::getInstance()->isMuted(from_id) && !LLMuteList::isLinden(av_name.getUserName()))  	{  		return false;  	} diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 7ac1df8e31..f47f0b4572 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -3234,36 +3234,39 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data)          return;      } -    LLFilenameAndTask* ft = new LLFilenameAndTask; -    ft->mTaskID = task_id;      // we can receive multiple task updates simultaneously, make sure we will not rewrite newer with older update -    msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, ft->mSerial); +    S16 serial = 0; +    msg->getS16Fast(_PREHASH_InventoryData, _PREHASH_Serial, serial); -    if (ft->mSerial == object->mInventorySerialNum -        && ft->mSerial < object->mExpectedInventorySerialNum) +    if (serial == object->mInventorySerialNum +        && serial < object->mExpectedInventorySerialNum)      {          // Loop Protection.          // We received same serial twice.          // Viewer did some changes to inventory that couldn't be saved server side          // or something went wrong to cause serial to be out of sync.          // Drop xfer and restart after some time, assign server's value as expected -        LL_WARNS() << "Task inventory serial might be out of sync, server serial: " << ft->mSerial << " client expected serial: " << object->mExpectedInventorySerialNum << LL_ENDL; -        object->mExpectedInventorySerialNum = ft->mSerial; +        LL_WARNS() << "Task inventory serial might be out of sync, server serial: " << serial << " client expected serial: " << object->mExpectedInventorySerialNum << LL_ENDL; +        object->mExpectedInventorySerialNum = serial;          object->fetchInventoryDelayed(INVENTORY_UPDATE_WAIT_TIME_DESYNC);      } -    else if (ft->mSerial < object->mExpectedInventorySerialNum) +    else if (serial < object->mExpectedInventorySerialNum)      {          // Out of date message, record to current serial for loop protection, but do not load it          // Drop xfer and restart after some time -        if (ft->mSerial < object->mInventorySerialNum) +        if (serial < object->mInventorySerialNum)          {              LL_WARNS() << "Task serial decreased. Potentially out of order packet or desync." << LL_ENDL;          } -        object->mInventorySerialNum = ft->mSerial; +        object->mInventorySerialNum = serial;          object->fetchInventoryDelayed(INVENTORY_UPDATE_WAIT_TIME_OUTDATED);      } -    else if (ft->mSerial >= object->mExpectedInventorySerialNum) +    else if (serial >= object->mExpectedInventorySerialNum)      { +        LLFilenameAndTask* ft = new LLFilenameAndTask; +        ft->mTaskID = task_id; +        ft->mSerial = serial; +                  // We received version we expected or newer. Load it.          object->mInventorySerialNum = ft->mSerial;          object->mExpectedInventorySerialNum = ft->mSerial; @@ -3298,7 +3301,7 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data)              object->mRegionp->getHost(),              TRUE,              &LLViewerObject::processTaskInvFile, -            (void**)ft, +            (void**)ft, // This takes ownership of ft              LLXferManager::HIGH_PRIORITY);          if (object->mInvRequestState == INVENTORY_XFER)          { diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index e930b58111..efc4ded79e 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -815,7 +815,10 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent)  	{  		virtual bool apply(LLViewerObject* objectp)  		{ -			objectp->boostTexturePriority(); +            if (objectp) +            { +                objectp->boostTexturePriority(); +            }  			return true;  		}  	} func; diff --git a/indra/newview/llviewerpartsource.cpp b/indra/newview/llviewerpartsource.cpp index f042040e98..1751ee1ebb 100644 --- a/indra/newview/llviewerpartsource.cpp +++ b/indra/newview/llviewerpartsource.cpp @@ -793,7 +793,7 @@ void LLViewerPartSourceBeam::update(const F32 dt)  		}  		LLViewerPart* part = new LLViewerPart(); -		part->init(this, mImagep, NULL); +		part->init(this, mImagep, updatePart);  		part->mFlags = LLPartData::LL_PART_INTERP_COLOR_MASK |  						LLPartData::LL_PART_INTERP_SCALE_MASK | diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index a4fbbb3e78..df3db9bb1d 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -509,6 +509,7 @@ void send_viewer_stats(bool include_preferences)      system["cpu_sse"] = gSysCPU.getSSEVersions();  	system["address_size"] = ADDRESS_SIZE;  	system["os_bitness"] = LLOSInfo::instance().getOSBitness(); +	system["hardware_concurrency"] = (LLSD::Integer) std::thread::hardware_concurrency();  	unsigned char MACAddress[MAC_ADDRESS_BYTES];  	LLUUID::getNodeID(MACAddress);  	std::string macAddressString = llformat("%02x-%02x-%02x-%02x-%02x-%02x", diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index e2de7ac825..7abb42dd8a 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -1252,7 +1252,6 @@ bool LLViewerTextEditor::onCopyToInvDialog(const LLSD& notification, const LLSD&  	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);  	if( 0 == option )  	{ -		LLUUID item_id = notification["payload"]["item_id"].asUUID();  		llwchar wc = llwchar(notification["payload"]["item_wc"].asInteger());  		LLInventoryItem* itemp = LLEmbeddedItems::getEmbeddedItemPtr(wc);  		if (itemp) diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index e3ac56d0d3..8a11c5cf8f 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1118,7 +1118,7 @@ void LLViewerFetchedTexture::init(bool firstinit)  	mLoadedCallbackDesiredDiscardLevel = S8_MAX;  	mPauseLoadedCallBacks = FALSE; -	mNeedsCreateTexture = FALSE; +	mNeedsCreateTexture = false;  	mIsRawImageValid = FALSE;  	mRawDiscardLevel = INVALID_DISCARD_LEVEL; @@ -1400,12 +1400,12 @@ void LLViewerFetchedTexture::addToCreateTexture()  	{  		//just update some variables, not to create a real GL texture.  		createGLTexture(mRawDiscardLevel, mRawImage, 0, FALSE); -		mNeedsCreateTexture = FALSE; +		mNeedsCreateTexture = false;  		destroyRawImage();  	}  	else if(!force_update && getDiscardLevel() > -1 && getDiscardLevel() <= mRawDiscardLevel)  	{ -		mNeedsCreateTexture = FALSE; +		mNeedsCreateTexture = false;  		destroyRawImage();  	}  	else @@ -1441,7 +1441,7 @@ void LLViewerFetchedTexture::addToCreateTexture()  						mRawDiscardLevel += i;  						if(mRawDiscardLevel >= getDiscardLevel() && getDiscardLevel() > 0)  						{ -							mNeedsCreateTexture = FALSE; +							mNeedsCreateTexture = false;  							destroyRawImage();  							return;  						} @@ -1473,7 +1473,7 @@ BOOL LLViewerFetchedTexture::preCreateTexture(S32 usename/*= 0*/)          destroyRawImage();          return FALSE;      } -    mNeedsCreateTexture = FALSE; +    mNeedsCreateTexture = false;      if (mRawImage.isNull())      { @@ -1609,14 +1609,14 @@ void LLViewerFetchedTexture::postCreateTexture()          destroyRawImage();      } -    mNeedsCreateTexture = FALSE; +    mNeedsCreateTexture = false;  }  void LLViewerFetchedTexture::scheduleCreateTexture()  {      if (!mNeedsCreateTexture)      { -        mNeedsCreateTexture = TRUE; +        mNeedsCreateTexture = true;          if (preCreateTexture())          {  #if LL_IMAGEGL_THREAD_CHECK @@ -1630,7 +1630,7 @@ void LLViewerFetchedTexture::scheduleCreateTexture()                  memcpy(data_copy, data, size);              }  #endif -            mNeedsCreateTexture = TRUE; +            mNeedsCreateTexture = true;              auto mainq = LLImageGLThread::sEnabled ? mMainQueue.lock() : nullptr;              if (mainq)              { diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index b953d7006b..2f5e0d01df 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -27,6 +27,7 @@  #ifndef LL_LLVIEWERTEXTURE_H					  #define LL_LLVIEWERTEXTURE_H +#include "llatomic.h"  #include "llgltexture.h"  #include "lltimer.h"  #include "llframetimer.h" @@ -528,7 +529,9 @@ protected:  	LLFrameTimer mStopFetchingTimer;	// Time since mDecodePriority == 0.f.  	BOOL  mInImageList;				// TRUE if image is in list (in which case don't reset priority!) -	BOOL  mNeedsCreateTexture;	 +	// This needs to be atomic, since it is written both in the main thread +	// and in the GL image worker thread... HB +	LLAtomicBool  mNeedsCreateTexture;	  	BOOL   mForSculpt ; //a flag if the texture is used as sculpt data.  	BOOL   mIsFetched ; //is loaded from remote or from cache, not generated locally. diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 3b391e311a..ddc11ac0bd 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1309,7 +1309,6 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi                                                            TRUE /* pick_transparent */,                                                             FALSE /* pick_rigged */); -					LLUUID object_id = pick_info.getObjectID();  					S32 object_face = pick_info.mObjectFace;  					std::string url = data; @@ -3435,6 +3434,59 @@ void LLViewerWindow::updateUI()  		root_view = mRootView;  	} +	static LLCachedControl<bool> dump_menu_holder(gSavedSettings, "DumpMenuHolderSize", false); +	if (dump_menu_holder) +	{ +		static bool init = false; +		static LLFrameTimer child_count_timer; +		static std::vector <std::string> child_vec; +		if (!init) +		{ +			child_count_timer.resetWithExpiry(5.f); +			init = true; +		} +		if (child_count_timer.hasExpired()) +		{ +			LL_INFOS() << "gMenuHolder child count: " << gMenuHolder->getChildCount() << LL_ENDL; +			std::vector<std::string> local_child_vec; +			LLView::child_list_t child_list = *gMenuHolder->getChildList(); +			for (auto child : child_list) +			{ +				local_child_vec.emplace_back(child->getName()); +			} +			if (!local_child_vec.empty() && local_child_vec != child_vec) +			{ +				std::vector<std::string> out_vec; +				std::sort(local_child_vec.begin(), local_child_vec.end()); +				std::sort(child_vec.begin(), child_vec.end()); +				std::set_difference(child_vec.begin(), child_vec.end(), local_child_vec.begin(), local_child_vec.end(), std::inserter(out_vec, out_vec.begin())); +				if (!out_vec.empty()) +				{ +					LL_INFOS() << "gMenuHolder removal diff size: '"<<out_vec.size() <<"' begin_child_diff"; +					for (auto str : out_vec) +					{ +						LL_CONT << " : " << str; +					} +					LL_CONT << " : end_child_diff" << LL_ENDL; +				} + +				out_vec.clear(); +				std::set_difference(local_child_vec.begin(), local_child_vec.end(), child_vec.begin(), child_vec.end(), std::inserter(out_vec, out_vec.begin())); +				if (!out_vec.empty()) +				{ +					LL_INFOS() << "gMenuHolder addition diff size: '" << out_vec.size() << "' begin_child_diff"; +					for (auto str : out_vec) +					{ +						LL_CONT << " : " << str; +					} +					LL_CONT << " : end_child_diff" << LL_ENDL; +				} +				child_vec.swap(local_child_vec); +			} +			child_count_timer.resetWithExpiry(5.f); +		} +	} +  	// only update mouse hover set when UI is visible (since we shouldn't send hover events to invisible UI  	if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))  	{ diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 176528cb56..17299b6c61 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -3528,14 +3528,15 @@ void LLVOAvatar::idleUpdateNameTagText(bool new_name)  void LLVOAvatar::addNameTagLine(const std::string& line, const LLColor4& color, S32 style, const LLFontGL* font, const bool use_ellipses)  { +    // extra width (NAMETAG_MAX_WIDTH) is for names only, not for chat  	llassert(mNameText);  	if (mVisibleChat)  	{ -		mNameText->addLabel(line); +		mNameText->addLabel(line, LLHUDNameTag::NAMETAG_MAX_WIDTH);  	}  	else  	{ -		mNameText->addLine(line, color, (LLFontGL::StyleFlags)style, font, use_ellipses); +		mNameText->addLine(line, color, (LLFontGL::StyleFlags)style, font, use_ellipses, LLHUDNameTag::NAMETAG_MAX_WIDTH);  	}      mNameIsSet |= !line.empty();  } diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 2ef2d66f18..6bb987ede4 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -797,7 +797,10 @@ void LLVoiceClient::addObserver(LLVoiceClientStatusObserver* observer)  void LLVoiceClient::removeObserver(LLVoiceClientStatusObserver* observer)  { -	if (mVoiceModule && mVoiceModule->singletoneInstanceExists()) mVoiceModule->removeObserver(observer); +    if (mVoiceModule) +    { +        mVoiceModule->removeObserver(observer); +    }  }  void LLVoiceClient::addObserver(LLFriendObserver* observer) @@ -807,7 +810,10 @@ void LLVoiceClient::addObserver(LLFriendObserver* observer)  void LLVoiceClient::removeObserver(LLFriendObserver* observer)  { -	if (mVoiceModule && mVoiceModule->singletoneInstanceExists()) mVoiceModule->removeObserver(observer); +    if (mVoiceModule) +    { +        mVoiceModule->removeObserver(observer); +    }  }  void LLVoiceClient::addObserver(LLVoiceClientParticipantObserver* observer) @@ -817,7 +823,10 @@ void LLVoiceClient::addObserver(LLVoiceClientParticipantObserver* observer)  void LLVoiceClient::removeObserver(LLVoiceClientParticipantObserver* observer)  { -	if (mVoiceModule && mVoiceModule->singletoneInstanceExists()) mVoiceModule->removeObserver(observer); +    if (mVoiceModule) +    { +        mVoiceModule->removeObserver(observer); +    }  }  std::string LLVoiceClient::sipURIFromID(const LLUUID &id) diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h index 246883b611..aa67502908 100644 --- a/indra/newview/llvoiceclient.h +++ b/indra/newview/llvoiceclient.h @@ -122,8 +122,6 @@ public:  	virtual const LLVoiceVersionInfo& getVersion()=0; -	virtual bool singletoneInstanceExists()=0; -	  	/////////////////////  	/// @name Tuning  	//@{ diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index ab90f2e482..c73f96da2d 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -4525,7 +4525,7 @@ void LLVivoxVoiceClient::messageEvent(  		{  			bool is_do_not_disturb = gAgent.isDoNotDisturb();  			bool is_muted = LLMuteList::getInstance()->isMuted(session->mCallerID, session->mName, LLMute::flagTextChat); -			bool is_linden = LLMuteList::getInstance()->isLinden(session->mName); +			bool is_linden = LLMuteList::isLinden(session->mName);  			LLChat chat;  			chat.mMuted = is_muted && !is_linden; @@ -5215,11 +5215,6 @@ void LLVivoxVoiceClient::declineInvite(std::string &sessionHandle)  	}  } -bool LLVivoxVoiceClient::singletoneInstanceExists() -{ -	return LLVivoxVoiceClient::instanceExists(); -} -  void LLVivoxVoiceClient::leaveNonSpatialChannel()  {      LL_DEBUGS("Voice") << "Request to leave spacial channel." << LL_ENDL; diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h index ebc3a62c35..0a785401c1 100644 --- a/indra/newview/llvoicevivox.h +++ b/indra/newview/llvoicevivox.h @@ -73,8 +73,6 @@ public:  	// Returns true if vivox has successfully logged in and is not in error state	  	virtual bool isVoiceWorking() const; -	 -	virtual bool singletoneInstanceExists();  	/////////////////////  	/// @name Tuning diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp index 1aa00bc894..909588367b 100644 --- a/indra/newview/llvosky.cpp +++ b/indra/newview/llvosky.cpp @@ -100,8 +100,8 @@ LLSkyTex::LLSkyTex() :  void LLSkyTex::init(bool isShiny)  {      mIsShiny = isShiny; -	mSkyData = new LLColor4[SKYTEX_RESOLUTION * SKYTEX_RESOLUTION]; -	mSkyDirs = new LLVector3[SKYTEX_RESOLUTION * SKYTEX_RESOLUTION]; +	mSkyData = new LLColor4[(U32)(SKYTEX_RESOLUTION * SKYTEX_RESOLUTION)]; +	mSkyDirs = new LLVector3[(U32)(SKYTEX_RESOLUTION * SKYTEX_RESOLUTION)];  	for (S32 i = 0; i < 2; ++i)  	{ diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index a4e0d367c8..2e7ccc8334 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -228,6 +228,9 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re      mColorChanged = FALSE;  	mSpotLightPriority = 0.f; +	mSkinInfoFailed = false; +	mSkinInfo = NULL; +  	mMediaImplList.resize(getNumTEs());  	mLastFetchedMediaVersion = -1;      mServerDrawableUpdateCount = 0; @@ -244,6 +247,8 @@ LLVOVolume::~LLVOVolume()  	delete mVolumeImpl;  	mVolumeImpl = NULL; +	gMeshRepo.unregisterMesh(this); +  	if(!mMediaImplList.empty())  	{  		for(U32 i = 0 ; i < mMediaImplList.size() ; i++) @@ -851,10 +856,7 @@ void LLVOVolume::updateTextureVirtualSize(bool forced)  	if (isSculpted())  	{ -		LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); -		LLUUID id =  sculpt_params->getSculptTexture(); -		 -		updateSculptTexture(); +        updateSculptTexture(); @@ -1095,10 +1097,15 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bo  			// if it's a mesh  			if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)  			{ +				if (mSkinInfo && mSkinInfo->mMeshID != volume_params.getSculptID()) +				{ +					mSkinInfo = NULL; +					mSkinInfoFailed = false; +				} +  				if (!getVolume()->isMeshAssetLoaded())  				{   					//load request not yet issued, request pipeline load this mesh -					LLUUID asset_id = volume_params.getSculptID();  					S32 available_lod = gMeshRepo.loadMesh(this, volume_params, lod, last_lod);  					if (available_lod != lod)  					{ @@ -1106,6 +1113,14 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bo  					}  				} +				if (!mSkinInfo && !mSkinInfoFailed) +				{ +					const LLMeshSkinInfo* skin_info = gMeshRepo.getSkinInfo(volume_params.getSculptID(), this); +					if (skin_info) +					{ +						notifySkinInfoLoaded(skin_info); +					} +				}  			}  			else // otherwise is sculptie  			{ @@ -1158,6 +1173,9 @@ void LLVOVolume::updateSculptTexture()  		{  			mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);  		} + +		mSkinInfoFailed = false; +		mSkinInfo = NULL;  	}  	else  	{ @@ -1212,6 +1230,20 @@ void LLVOVolume::notifyMeshLoaded()      updateVisualComplexity();  } +void LLVOVolume::notifySkinInfoLoaded(const LLMeshSkinInfo* skin) +{ +	mSkinInfoFailed = false; +	mSkinInfo = skin; + +	notifyMeshLoaded(); +} + +void LLVOVolume::notifySkinInfoUnavailable() +{ +	mSkinInfoFailed = true; +	mSkinInfo = nullptr; +} +  // sculpt replaces generate() for sculpted surfaces  void LLVOVolume::sculpt()  {	 @@ -3645,7 +3677,7 @@ const LLMeshSkinInfo* LLVOVolume::getSkinInfo() const  {      if (getVolume())      { -        return gMeshRepo.getSkinInfo(getMeshID(), this); +         return mSkinInfo;      }      else      { diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 01ad40274b..59599ddc0c 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -353,6 +353,8 @@ public:      void updateVisualComplexity();  	void notifyMeshLoaded(); +	void notifySkinInfoLoaded(const LLMeshSkinInfo* skin); +	void notifySkinInfoUnavailable();  	// Returns 'true' iff the media data for this object is in flight  	bool isMediaDataBeingFetched() const; @@ -437,6 +439,8 @@ private:  	LLPointer<LLRiggedVolume> mRiggedVolume; +	bool mSkinInfoFailed; +	LLConstPointer<LLMeshSkinInfo> mSkinInfo;  	// statics  public:  	static F32 sLODSlopDistanceFactor;// Changing this to zero, effectively disables the LOD transition slop diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index bf4db81475..89b74ae962 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -92,17 +92,77 @@ LLPanelWearableListItem::LLPanelWearableListItem(LLViewerInventoryItem* item, co  //////////////////////////////////////////////////////////////////////////  //////////////////////////////////////////////////////////////////////////  ////////////////////////////////////////////////////////////////////////// +static LLWidgetNameRegistry::StaticRegistrar sRegisterPanelWearableOutfitItem(&typeid(LLPanelWearableOutfitItem::Params), "wearable_outfit_list_item"); + +LLPanelWearableOutfitItem::Params::Params() +:   add_btn("add_btn"), +    remove_btn("remove_btn") +{ +} + +BOOL LLPanelWearableOutfitItem::postBuild() +{ +    LLPanelWearableListItem::postBuild(); +     +    LLViewerInventoryItem* inv_item = getItem(); +    mShowWidgets &= (inv_item->getType() != LLAssetType::AT_BODYPART); +    if(mShowWidgets) +    { +        addWidgetToRightSide("add_wearable"); +        addWidgetToRightSide("remove_wearable"); + +        childSetAction("add_wearable", boost::bind(&LLPanelWearableOutfitItem::onAddWearable, this)); +        childSetAction("remove_wearable", boost::bind(&LLPanelWearableOutfitItem::onRemoveWearable, this)); + +        setWidgetsVisible(false); +        reshapeWidgets(); +    } +    return TRUE; +} + +BOOL LLPanelWearableOutfitItem::handleDoubleClick(S32 x, S32 y, MASK mask) +{ +    if(!mShowWidgets) +    { +        return LLPanelWearableListItem::handleDoubleClick(x, y, mask); +    } + +    if(LLAppearanceMgr::instance().isLinkedInCOF(mInventoryItemUUID)) +    { +        onRemoveWearable(); +    } +    else +    { +        onAddWearable(); +    } +    return TRUE; +} + +void LLPanelWearableOutfitItem::onAddWearable() +{ +    setWidgetsVisible(false); +    reshapeWidgets(); +    LLAppearanceMgr::instance().wearItemOnAvatar(mInventoryItemUUID, true, false); +} + +void LLPanelWearableOutfitItem::onRemoveWearable() +{ +    setWidgetsVisible(false); +    reshapeWidgets(); +    LLAppearanceMgr::instance().removeItemFromAvatar(mInventoryItemUUID); +}  // static  LLPanelWearableOutfitItem* LLPanelWearableOutfitItem::create(LLViewerInventoryItem* item, -															 bool worn_indication_enabled) +															 bool worn_indication_enabled, +                                                             bool show_widgets)  {  	LLPanelWearableOutfitItem* list_item = NULL;  	if (item)  	{ -		const LLPanelInventoryListItemBase::Params& params = LLUICtrlFactory::getDefaultParams<LLPanelInventoryListItemBase>(); +		const LLPanelWearableOutfitItem::Params& params = LLUICtrlFactory::getDefaultParams<LLPanelWearableOutfitItem>(); -		list_item = new LLPanelWearableOutfitItem(item, worn_indication_enabled, params); +		list_item = new LLPanelWearableOutfitItem(item, worn_indication_enabled, params, show_widgets);  		list_item->initFromParams(params);  		list_item->postBuild();  	} @@ -110,11 +170,23 @@ LLPanelWearableOutfitItem* LLPanelWearableOutfitItem::create(LLViewerInventoryIt  }  LLPanelWearableOutfitItem::LLPanelWearableOutfitItem(LLViewerInventoryItem* item, -													 bool worn_indication_enabled, -													 const LLPanelWearableOutfitItem::Params& params) -: LLPanelInventoryListItemBase(item, params) +                                                     bool worn_indication_enabled, +                                                     const LLPanelWearableOutfitItem::Params& params, +                                                     bool show_widgets) +: LLPanelWearableListItem(item, params)  , mWornIndicationEnabled(worn_indication_enabled) +, mShowWidgets(show_widgets)  { +    if(mShowWidgets) +    { +        LLButton::Params button_params = params.add_btn; +        applyXUILayout(button_params, this); +        addChild(LLUICtrlFactory::create<LLButton>(button_params)); + +        button_params = params.remove_btn; +        applyXUILayout(button_params, this); +        addChild(LLUICtrlFactory::create<LLButton>(button_params)); +    }  }  // virtual @@ -127,11 +199,22 @@ void LLPanelWearableOutfitItem::updateItem(const std::string& name,  	// We don't use get_is_item_worn() here because this update is triggered by  	// an inventory observer upon link in COF beind added or removed so actual  	// worn status of a linked item may still remain unchanged. -	if (mWornIndicationEnabled && LLAppearanceMgr::instance().isLinkedInCOF(mInventoryItemUUID)) +    bool is_worn = LLAppearanceMgr::instance().isLinkedInCOF(mInventoryItemUUID); +	if (mWornIndicationEnabled && is_worn)  	{  		search_label += LLTrans::getString("worn");  		item_state = IS_WORN;  	} +    if(mShowWidgets) +    { +        setShowWidget("add_wearable", !is_worn); +        setShowWidget("remove_wearable", is_worn); +        if(mHovered) +        { +            setWidgetsVisible(true); +            reshapeWidgets(); +        } +    }  	LLPanelInventoryListItemBase::updateItem(search_label, item_state);  } @@ -634,6 +717,7 @@ static const LLDefaultChildRegistry::Register<LLWearableItemsList> r("wearable_i  LLWearableItemsList::Params::Params()  :	standalone("standalone", true)  ,	worn_indication_enabled("worn_indication_enabled", true) +,   show_item_widgets("show_item_widgets", false)  {}  LLWearableItemsList::LLWearableItemsList(const LLWearableItemsList::Params& p) @@ -649,6 +733,7 @@ LLWearableItemsList::LLWearableItemsList(const LLWearableItemsList::Params& p)  	}  	mWornIndicationEnabled = p.worn_indication_enabled;  	setNoItemsCommentText(LLTrans::getString("LoadingData")); +    mShowItemWidgets = p.show_item_widgets;  }  // virtual @@ -665,7 +750,7 @@ LLPanel* LLWearableItemsList::createNewItem(LLViewerInventoryItem* item)          return NULL;      } -    return LLPanelWearableOutfitItem::create(item, mWornIndicationEnabled); +    return LLPanelWearableOutfitItem::create(item, mWornIndicationEnabled, mShowItemWidgets);  }  void LLWearableItemsList::updateList(const LLUUID& category_id) diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h index ba8488b237..f7774a7086 100644 --- a/indra/newview/llwearableitemslist.h +++ b/indra/newview/llwearableitemslist.h @@ -72,12 +72,23 @@ protected:   * Extends LLPanelInventoryListItemBase with handling   * double click to wear the item.   */ -class LLPanelWearableOutfitItem : public LLPanelInventoryListItemBase +class LLPanelWearableOutfitItem : public LLPanelWearableListItem  {  	LOG_CLASS(LLPanelWearableOutfitItem);  public: +    struct Params : public LLInitParam::Block<Params, LLPanelWearableListItem::Params> +    { +        Optional<LLButton::Params>   add_btn, remove_btn; + +        Params(); +    }; + +    BOOL postBuild(); +    BOOL handleDoubleClick(S32 x, S32 y, MASK mask); +  	static LLPanelWearableOutfitItem* create(LLViewerInventoryItem* item, -											 bool worn_indication_enabled); +											 bool worn_indication_enabled, +                                             bool show_widgets);  	/**  	 * Updates item name and (worn) suffix. @@ -85,12 +96,16 @@ public:  	/*virtual*/ void updateItem(const std::string& name,  								EItemState item_state = IS_DEFAULT); +    void onAddWearable(); +    void onRemoveWearable(); +  protected:  	LLPanelWearableOutfitItem(LLViewerInventoryItem* item, -							  bool worn_indication_enabled, const Params& params); +							  bool worn_indication_enabled, const Params& params, bool show_widgets = false);  private:  	bool	mWornIndicationEnabled; +    bool mShowWidgets;  };  class LLPanelDeletableWearableListItem : public LLPanelWearableListItem @@ -442,6 +457,7 @@ public:  	{  		Optional<bool> standalone;  		Optional<bool> worn_indication_enabled; +        Optional<bool> show_item_widgets;  		Params();  	}; @@ -482,6 +498,7 @@ protected:  	bool mIsStandalone;  	bool mWornIndicationEnabled; +    bool mShowItemWidgets;  	ESortOrder		mSortOrder; diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index cfd79dfd5a..3201440b95 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -293,13 +293,13 @@ void LLWorld::removeRegion(const LLHost &host)  	mRegionRemovedSignal(regionp); -	delete regionp; -  	updateWaterObjects();  	//double check all objects of this region are removed.  	gObjectList.clearAllMapObjectsInRegion(regionp) ;  	//llassert_always(!gObjectList.hasMapObjectInRegion(regionp)) ; + +	delete regionp; // Delete last to prevent use after free  } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 13d6966723..d00ac5db76 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -1775,20 +1775,17 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable)  void LLPipeline::removeMutedAVsLights(LLVOAvatar* muted_avatar)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; -    light_set_t::iterator iter = gPipeline.mNearbyLights.begin(); - -    while (iter != gPipeline.mNearbyLights.end()) -    { -        if (iter->drawable->getVObj()->isAttachment() && iter->drawable->getVObj()->getAvatar() == muted_avatar) -        { -            gPipeline.mLights.erase(iter->drawable); -            iter = gPipeline.mNearbyLights.erase(iter); -        } -        else -        { -            iter++; -        } -    } +	for (light_set_t::iterator iter = gPipeline.mNearbyLights.begin(); +		 iter != gPipeline.mNearbyLights.end(); iter++) +	{ +        const LLViewerObject *vobj = iter->drawable->getVObj(); +        if (vobj && vobj->getAvatar() +            && vobj->isAttachment() && vobj->getAvatar() == muted_avatar) +		{ +			gPipeline.mLights.erase(iter->drawable); +			gPipeline.mNearbyLights.erase(iter); +		} +	}  }  U32 LLPipeline::addObject(LLViewerObject *vobj) diff --git a/indra/newview/skins/default/textures/icons/add_icon.png b/indra/newview/skins/default/textures/icons/add_icon.png Binary files differnew file mode 100644 index 0000000000..cb68ee8e16 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/add_icon.png diff --git a/indra/newview/skins/default/textures/icons/remove_icon.png b/indra/newview/skins/default/textures/icons/remove_icon.png Binary files differnew file mode 100644 index 0000000000..6e62ee33f4 --- /dev/null +++ b/indra/newview/skins/default/textures/icons/remove_icon.png diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 4429a1677e..1f2c0867c4 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -743,6 +743,9 @@ with the same filename but different name    <texture name="Wearables_Divider" file_name="windows/Wearables_Divider.png" preload="false" /> +  <texture name="Add_Icon" file_name="icons/add_icon.png" preload="false" /> +  <texture name="Remove_Icon" file_name="icons/remove_icon.png" preload="false" /> +    <texture name="Web_Profile_Off" file_name="icons/Web_Profile_Off.png" preload="false" />    <texture name="WellButton_Lit" file_name="bottomtray/WellButton_Lit.png"  preload="true" scale.left="4" scale.top="19" scale.right="28" scale.bottom="4" /> diff --git a/indra/newview/skins/default/xui/de/floater_tools.xml b/indra/newview/skins/default/xui/de/floater_tools.xml index a4dfde66bc..f6208e11a5 100644 --- a/indra/newview/skins/default/xui/de/floater_tools.xml +++ b/indra/newview/skins/default/xui/de/floater_tools.xml @@ -40,7 +40,7 @@  		Klicken und ziehen, um Land auszuwählen  	</floater.string>  	<floater.string name="status_selectcount"> -		[OBJ_COUNT] Objekte ausgewählt, Auswirkung auf Land [LAND_IMPACT] +		[OBJ_COUNT] Objekte ausgewählt, Auswirkung auf Land [LAND_IMPACT] [secondlife:///app/openfloater/object_weights ?]  	</floater.string>  	<floater.string name="status_remaining_capacity">  		Verbleibende Kapazität [LAND_CAPACITY]. diff --git a/indra/newview/skins/default/xui/en/floater_display_name.xml b/indra/newview/skins/default/xui/en/floater_display_name.xml index 3c8f415860..f3431da858 100644 --- a/indra/newview/skins/default/xui/en/floater_display_name.xml +++ b/indra/newview/skins/default/xui/en/floater_display_name.xml @@ -56,7 +56,7 @@        max_length_chars="31"        height="20"        top_pad="5" -      left="50" /> +      left_delta="0" />  	<text         top_pad="15"         left="25" @@ -72,23 +72,33 @@        max_length_chars="31"        height="20"        top_pad="5" -      left="50" /> +      left_delta="0" /> +    <button +     label="Reset" +     layout="topleft" +     font="SansSerif" +     width="120" +     height="23" +     top_pad="40" +     left_delta="0" +     name="reset_btn" +     tool_tip="Use Username as a Display Name" />      <button       height="23"       label="Save"       layout="topleft"       font="SansSerif" -     left="35" +     left_pad="35"       name="save_btn"       tool_tip="Save your new Display Name"  -     top_pad="40" +     top_delta="0"       width="120" />      <button       height="23"       label="Cancel"       font="SansSerif"       layout="topleft" -     left_pad="125" +     left_pad="5"       name="cancel_btn"       width="120" />  </floater> diff --git a/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml index 45e16c59ae..850e1be372 100644 --- a/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml +++ b/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml @@ -323,7 +323,6 @@          follows="left|top"          decimal_digits="0"          increment="1" -        control_name="Edit Cost"          name="Edit Cost"          label="Price:"          label_width="100" diff --git a/indra/newview/skins/default/xui/en/floater_object_weights.xml b/indra/newview/skins/default/xui/en/floater_object_weights.xml index eb283a1043..889efa061c 100644 --- a/indra/newview/skins/default/xui/en/floater_object_weights.xml +++ b/indra/newview/skins/default/xui/en/floater_object_weights.xml @@ -2,7 +2,7 @@  <floater   can_close="true"   can_tear_off="false" - height="315" + height="289"   help_topic="object_weights"   layout="topleft"   name="object_weights" @@ -320,23 +320,4 @@       top_delta="0"       value="Total capacity"       width="130" /> -    <view_border -     bevel_style="none" -     follows="top|left" -     height="0" -     layout="topleft" -     left="10" -     name="land_impacts_text_border" -     top_pad="5" -     width="180"/> - -    <text -     follows="left|top" -     height="16" -     layout="topleft" -     left="10" -     name="help_SLURL" -     top_pad="10" -     value="[secondlife:///app/help/object_weights What is all this?...]" -     width="180" />  </floater> diff --git a/indra/newview/skins/default/xui/en/floater_openobject.xml b/indra/newview/skins/default/xui/en/floater_openobject.xml index 912db80bcc..ec03d7d32c 100644 --- a/indra/newview/skins/default/xui/en/floater_openobject.xml +++ b/indra/newview/skins/default/xui/en/floater_openobject.xml @@ -3,7 +3,7 @@   legacy_header_height="18"   can_resize="true"   default_tab_group="1" - height="370" + height="350"   layout="topleft"   min_height="190"   min_width="285" @@ -31,62 +31,18 @@       background_visible="false"       draw_border="false"       follows="all" -     height="240" +     height="265"       layout="topleft" +     show_root_folder="false"       left="10"       name="object_contents"       top_pad="0"       width="284" /> -  	<view_border -     bevel_style="none" -     follows="bottom|left" -     height="50" -     highlight_light_color="0.6 0.6 0.6" -     layout="topleft" -     left="10" -     name="border" -     top_pad="5" -     width="270"/>  -  	<text -  	 follows="bottom|left" -  	 height="15" -  	 layout="topleft" -  	 left="15" -  	 name="border_note" -  	 text_color="White" -  	 top_delta="5"> -  	 	Copy to inventory and wear -    </text>   - 	<button -     follows="bottom|left" -     height="23" -     label="Add to outfit" -     label_selected="Add to outfit" -     layout="topleft" - 	 left="15"     -     name="copy_and_wear_button" 	 - 	 top_pad="3"	 -     width="135"> -        <button.commit_callback -         function="OpenObject.MoveAndWear" /> -    </button> -	<button -     follows="bottom|left" -     height="23" -     label="Replace outfit" -     label_selected="Replace outfit" -     layout="topleft" -     left_pad="5" -     name="copy_and_replace_button" -     width="120"> -        <button.commit_callback -         function="OpenObject.ReplaceOutfit" /> -    </button>        <button       follows="bottom|left"       height="23"       label="Only copy to inventory" -     label_selected="Only copy to inventory" +     label_selected="Copy to inventory"       layout="topleft"       left="15"       name="copy_to_inventory_button" diff --git a/indra/newview/skins/default/xui/en/floater_pathfinding_linksets.xml b/indra/newview/skins/default/xui/en/floater_pathfinding_linksets.xml index 41384a77b8..59117c0178 100644 --- a/indra/newview/skins/default/xui/en/floater_pathfinding_linksets.xml +++ b/indra/newview/skins/default/xui/en/floater_pathfinding_linksets.xml @@ -82,17 +82,20 @@          width="62">        Name      </text> -    <line_editor -        border_style="line" -        border_thickness="1" -        follows="left|top" -        height="20" -        layout="topleft" -        left_pad="0" -        top_pad="-18" -        max_length_chars="255" -        name="filter_by_name" -        width="161" /> + +    <search_editor +       follows="left|top" +       search_button_visible="false" +       height="20" +       text_readonly_color="DkGray" +       label="Objects by Name" +       layout="topleft" +       left_pad="0" +       top_pad="-18" +       name="filter_by_name" +       select_on_focus="true" +       width="161"> +    </search_editor>      <text          name="linksets_desc_label"          height="13" @@ -108,17 +111,19 @@          width="88">        Description      </text> -    <line_editor -        border_style="line" -        border_thickness="1" -        follows="left|top" -        height="20" -        layout="topleft" -        left_pad="0" -        top_pad="-17" -        max_length_chars="255" -        name="filter_by_description" -        width="162" /> +    <search_editor +       follows="left|top" +       search_button_visible="false" +       height="20" +       text_readonly_color="DkGray" +       label="Objects by Description" +       layout="topleft" +       left_pad="0" +       top_pad="-17" +       name="filter_by_description" +       select_on_focus="true" +       width="162"> +    </search_editor>      <combo_box          height="20"          layout="topleft" diff --git a/indra/newview/skins/default/xui/en/floater_settings_debug.xml b/indra/newview/skins/default/xui/en/floater_settings_debug.xml index 3ed2bd7206..e4fda5cd10 100644 --- a/indra/newview/skins/default/xui/en/floater_settings_debug.xml +++ b/indra/newview/skins/default/xui/en/floater_settings_debug.xml @@ -2,41 +2,79 @@  <floater   legacy_header_height="18"   can_minimize="false" - height="215" + height="360" + min_height="367"   layout="topleft"   name="settings_debug"   help_topic="settings_debug"   title="DEBUG SETTINGS" - width="350"> -    <combo_box -     allow_text_entry="true" -     follows="top|left" -     height="22" -     layout="topleft" -     left="15" -     max_chars="255" -     name="settings_combo" -     top="30" -     width="320"> -      <combo_box.commit_callback -       function="SettingSelect" /> -    </combo_box> -    <text_editor -     enabled="false" -     height="60" -     layout="topleft" -     left_delta="0" -     name="comment_text" -     top_pad="10" -     width="320" -     word_wrap="true" /> + reuse_instance="true" + can_resize="true" + min_width="550" + width="570"> +  <filter_editor +   follows="left|top|right" +   height="23" +   layout="topleft" +   left="10" +   right="-10" +   label="Enter search text" +   max_length_chars="300" +   name="filter_input" +   text_pad_left="10" +   top="30" /> +  <scroll_list +   column_padding="0" +   draw_heading="true" +   draw_stripes="false" +   heading_height="23" +   height="266" +   layout="topleft" +   search_column="1" +   left="10" +   follows="left|top|bottom" +   name="setting_list" +   top_pad="2" +   width="300"> +    <scroll_list.columns +     name="changed_setting" +     relative_width="0.05"  /> +    <scroll_list.columns +     label="Setting" +     name="setting" /> +  </scroll_list> +  <text +   type="string" +   length="1" +   follows="left|top" +   height="16" +   layout="topleft" +   name="setting_name_txt" +   font="SansSerifSmallBold" +   top_delta="8" +   left_pad="10" +   visible="false" +   use_ellipses="true" +   text_color="White" +   width="240"> +    Debug setting name +  </text> +  <text_editor +   enabled="false" +   height="75" +   layout="topleft" +   visible="false" +   name="comment_text" +   follows="left|top" +   width="240" +   top_delta="20" +   word_wrap="true" />    <radio_group     follows="top|left"     height="30"     layout="topleft" -   left_delta="0"     name="boolean_combo" -   top_pad="10" +   top_pad="15"     visible="false"     tab_stop="true"      width="100"> @@ -55,21 +93,25 @@    </radio_group>      <line_editor       height="20" +     follows="top|left"       layout="topleft"       left_delta="0"       name="val_text"       top_delta="0"       visible="false" -     width="300" > +     width="220" >        <line_editor.commit_callback         function="CommitSettings" />      </line_editor>      <color_swatch -     bottom="185" +     top_delta="0" +     left_delta="0" +     follows="top|left"       can_apply_immediately="true"       height="55"       name="val_color_swatch"       label="Color" +     visible="false"       layout="topleft"       width="37" >        <color_swatch.commit_callback @@ -79,10 +121,11 @@       height="20"       label="x"       layout="topleft" +     follows="top|left"       left_delta="0"       max_val="1e+007"       name="val_spinner_1" -     top_delta="10" +     top_delta="5"       visible="false"       width="120" >        <spinner.commit_callback @@ -92,10 +135,11 @@       height="20"       label="x"       layout="topleft" -     left_pad="15" +     follows="top|left" +     left_delta="0"       max_val="1e+007"       name="val_spinner_2" -     top_delta="0" +     top_pad="10"       visible="false"       width="120">        <spinner.commit_callback @@ -105,10 +149,11 @@       height="20"       label="x"       layout="topleft" -     left="15" +     follows="top|left" +     left_delta="0"       max_val="1e+007"       name="val_spinner_3" -     top="160" +     top_pad="10"       visible="false"       width="120">        <spinner.commit_callback @@ -118,10 +163,11 @@       height="20"       label="x"       layout="topleft" -     left_pad="15" +     follows="top|left" +     left_delta="0"       max_val="1e+007"       name="val_spinner_4" -     top_delta="0" +     top_pad="10"       visible="false"       width="120" >        <spinner.commit_callback @@ -130,12 +176,26 @@      <button       height="22"       label="Reset to default" +     follows="left|top"       layout="topleft" -     left="15" +     left_delta="0"       name="default_btn" -     top="186" +     visible="false" +     top_pad="10"       width="150" >        <button.commit_callback         function="ClickDefault" />      </button> +    <check_box +      control_name="DebugSettingsHideDefault" +      height="16" +      initial_value="true" +      label="Show changed settings only" +      layout="topleft" +      top_pad="10" +      left="10" +      follows="left|bottom" +      name="hide_default" +      width="330"> +    </check_box>  </floater> diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index ade79b8884..d9b0ac0060 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -1140,7 +1140,6 @@ even though the user gets a free copy.        decimal_digits="0"        increment="1"        left_pad="0" -      control_name="Edit Cost"        name="Edit Cost"        label="L$"        label_width="15" diff --git a/indra/newview/skins/default/xui/en/menu_participant_view.xml b/indra/newview/skins/default/xui/en/menu_participant_view.xml index 7ea87ee05c..b9750284cd 100644 --- a/indra/newview/skins/default/xui/en/menu_participant_view.xml +++ b/indra/newview/skins/default/xui/en/menu_participant_view.xml @@ -90,7 +90,7 @@           parameter="conversation_log" />      </menu_item_check>      <menu_item_separator layout="topleft" /> -    <menu_item_check name="Translate_chat" label="Translate Nearby chat"> +    <menu_item_check name="Translate_chat" label="Translate chat">          <menu_item_check.on_click           function="IMFloaterContainer.Action"            parameter="Translating.Toggle" /> diff --git a/indra/newview/skins/default/xui/en/outfit_accordion_tab.xml b/indra/newview/skins/default/xui/en/outfit_accordion_tab.xml index 2a24c74feb..d74dca8b95 100644 --- a/indra/newview/skins/default/xui/en/outfit_accordion_tab.xml +++ b/indra/newview/skins/default/xui/en/outfit_accordion_tab.xml @@ -18,6 +18,7 @@       follows="all"       keep_one_selected="true"       multi_select="true" +     show_item_widgets="true"       name="wearable_items_list"       translate="false"       standalone="false" diff --git a/indra/newview/skins/default/xui/en/panel_media_settings_general.xml b/indra/newview/skins/default/xui/en/panel_media_settings_general.xml index 2316beeb36..4c566dc60a 100644 --- a/indra/newview/skins/default/xui/en/panel_media_settings_general.xml +++ b/indra/newview/skins/default/xui/en/panel_media_settings_general.xml @@ -92,10 +92,7 @@     label="Reset"     left_delta="233"      name="current_url_reset_btn"  -   width="110" >  -   <button.commit_callback -	     function="Media.ResetCurrentUrl"/> -  </button> +   width="110"/>    <check_box      bottom_delta="-25"      enabled="true"  diff --git a/indra/newview/skins/default/xui/en/panel_outfits_wearing.xml b/indra/newview/skins/default/xui/en/panel_outfits_wearing.xml index 42a7974316..b2dc975c6e 100644 --- a/indra/newview/skins/default/xui/en/panel_outfits_wearing.xml +++ b/indra/newview/skins/default/xui/en/panel_outfits_wearing.xml @@ -36,6 +36,7 @@       left="3"       multi_select="true"       name="cof_items_list" +     show_item_widgets="true"       standalone="false"       top="0"       width="309" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml b/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml index 2ec5cef640..ef08fdf7c4 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml @@ -19,7 +19,7 @@        follows="left|top"        height="23"        label="Clear History" -      tool_tip="Clear login image, last location, teleport history, web and texture cache" +      tool_tip="Clear search and teleport history, web and texture cache"        layout="topleft"        left="30"        name="clear_cache" diff --git a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml index 551b477876..777b37d666 100644 --- a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml +++ b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml @@ -9,9 +9,13 @@   follows="all"   layout="topleft"  > +  <!-- +  Date from server comes already converted to stl timezone, +  so display it as an UTC+0 +  -->     <string       name="date_format" -    value="SL birthdate: [mth,datetime,slt] [day,datetime,slt], [year,datetime,slt]" /> +    value="SL birthdate: [mth,datetime,utc] [day,datetime,utc], [year,datetime,utc]" />     <string      name="age_format"      value="[AGE]" /> diff --git a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml index 9a68479d05..35d14251c7 100644 --- a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml +++ b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml @@ -450,7 +450,6 @@          follows="left|top"          decimal_digits="0"          increment="1" -        control_name="Edit Cost"          name="Edit Cost"          label="Price: L$"          label_width="75" @@ -461,8 +460,72 @@          max_val="999999999"          top_pad="10"          tool_tip="Object cost." /> -    </panel> - +      <text +        type="string" +        length="1" +        follows="left|top" +        height="10" +        layout="topleft" +        left="10" +        name="BaseMaskDebug" +        text_color="White" +        top_pad="30" +        width="130"> +        B: +      </text> +      <text +        type="string" +        length="1" +        follows="left|top" +        height="10" +        layout="topleft" +        left_delta="60" +        name="OwnerMaskDebug" +        text_color="White" +        top_delta="0" +        width="270"> +        O: +      </text> +      <text +        type="string" +        length="1" +        follows="left|top" +        height="10" +        layout="topleft" +        left_delta="60" +        name="GroupMaskDebug" +        text_color="White" +        top_delta="0" +        width="210"> +        G: +      </text> +      <text +        type="string" +        length="1" +        follows="left|top" +        height="10" +        layout="topleft" +        left_delta="60" +        name="EveryoneMaskDebug" +        text_color="White" +        top_delta="0" +        width="150"> +        E: +      </text> +      <text +       type="string" +       length="1" +       follows="left|top" +       height="10" +       layout="topleft" +       left_delta="60" +       name="NextMaskDebug" +       text_color="White" +       top_delta="0" +       width="90"> +        N: +      </text> +    </panel>       </scroll_container>    <panel      height="30" diff --git a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml index 1c9d750aa6..0b32215964 100644 --- a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml +++ b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml @@ -454,7 +454,6 @@          increment="1"          top_pad="10"          left="120" -        control_name="Edit Cost"          name="Edit Cost"          label="Price: L$"          label_width="73"				 diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index cf5d98aa9a..9cb5115bef 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -126,7 +126,7 @@ http://secondlife.com/download  For more information, see our FAQ below:  http://secondlife.com/viewer-access-faq</string> -	<string name="LoginFailed">Grid emergency login failure. +	<string name="LoginFailed">Login failure.  If you feel this is an error, please contact support@secondlife.com.</string>  	<string name="LoginIntermediateOptionalUpdateAvailable">Optional viewer update available: [VERSION]</string>  	<string name="LoginFailedRequiredUpdate">Required viewer update: [VERSION]</string> @@ -3983,7 +3983,7 @@ Please check http://status.secondlifegrid.net to see if there is a known problem    <string name="Premium_PlusMembership">Premium Plus</string>    <string name="InternalMembership">Internal</string> <!-- No need to translate --> -  <string name="MembershipUpgradeText">Upgrade to Premium</string> +  <string name="MembershipUpgradeText">Change membership plan...</string>    <string name="MembershipPremiumText">My Premium membership</string>    <!-- Question strings for delete items notifications --> diff --git a/indra/newview/skins/default/xui/en/widgets/filter_editor.xml b/indra/newview/skins/default/xui/en/widgets/filter_editor.xml index 1c4822b8d5..9c80deeafc 100644 --- a/indra/newview/skins/default/xui/en/widgets/filter_editor.xml +++ b/indra/newview/skins/default/xui/en/widgets/filter_editor.xml @@ -6,7 +6,7 @@    text_pad_left="7"    select_on_focus="true"    text_tentative_color="TextFgTentativeColor" -  highlight_text_field="false" +  highlight_text_field="true"    background_image="TextField_Search_Off"    background_image_disabled="TextField_Search_Disabled"    background_image_focused="TextField_Search_Active" diff --git a/indra/newview/skins/default/xui/en/widgets/search_editor.xml b/indra/newview/skins/default/xui/en/widgets/search_editor.xml index dc5a07bf4f..18d99f1ed1 100644 --- a/indra/newview/skins/default/xui/en/widgets/search_editor.xml +++ b/indra/newview/skins/default/xui/en/widgets/search_editor.xml @@ -7,7 +7,7 @@    text_pad_right="6"     select_on_focus="true"    text_tentative_color="TextFgTentativeColor" -  highlight_text_field="false" +  highlight_text_field="true"    background_image="TextField_Search_Off"    background_image_disabled="TextField_Search_Disabled"    background_image_focused="TextField_Search_Active" diff --git a/indra/newview/skins/default/xui/en/widgets/wearable_outfit_list_item.xml b/indra/newview/skins/default/xui/en/widgets/wearable_outfit_list_item.xml new file mode 100644 index 0000000000..cd84b91b1f --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/wearable_outfit_list_item.xml @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<inventory_list_item +  follows="top|right|left" +  height="20" +  name="inventory_item" +  tab_stop="false"  +  hover_image="ListItem_Over" +  selected_image="ListItem_Select" +  separator_image="Wearables_Divider"  +  width="380"> +  <!-- DEFAULT style for inventory list item --> +  <default_style +   font="SansSerifSmall" +   font.style="NORMAL" /> + +  <!-- style for inventory list item WORN on avatar --> +  <worn_style +   font="SansSerifSmall" +   font.style="BOLD" +   color="EmphasisColor" /> +  <item_icon +    height="16" +    follows="top|left" +    image_name="Inv_Object" +    layout="topleft" +    left="0" +    name="item_icon" +    top="0" +    width="16" /> +  <item_name +    follows="left|right" +    height="20" +    layout="topleft" +    left="21" +    parse_urls="false" +    use_ellipses="true" +    name="item_name" +    text_color="white" +    top="4" +    value="..." +    width="359" /> +    <add_btn +     name="add_wearable" +     layout="topleft" +     follows="top|right" +     image_unselected="Add_Icon" +     image_selected="Add_Icon" +     top="1" +     left="0" +     height="16" +     width="16" +     tab_stop="false" /> +    <remove_btn +     name="remove_wearable" +     layout="topleft" +     follows="top|right" +     image_unselected="Remove_Icon" +     image_selected="Remove_Icon" +     top="1" +     left="26" +     height="16" +     width="16" +     tab_stop="false" /> +</inventory_list_item> diff --git a/indra/newview/skins/default/xui/es/floater_tools.xml b/indra/newview/skins/default/xui/es/floater_tools.xml index 6fce98472d..ffa85a2f04 100644 --- a/indra/newview/skins/default/xui/es/floater_tools.xml +++ b/indra/newview/skins/default/xui/es/floater_tools.xml @@ -25,7 +25,7 @@  		Pulsa y arrastra para seleccionar el terreno.  	</floater.string>  	<floater.string name="status_selectcount"> -		[OBJ_COUNT] objetos seleccionados, impacto en el terreno [LAND_IMPACT] +		[OBJ_COUNT] objetos seleccionados, impacto en el terreno [LAND_IMPACT] [secondlife:///app/openfloater/object_weights ?]  	</floater.string>  	<floater.string name="status_remaining_capacity">  		Capacidad restante [LAND_CAPACITY]. diff --git a/indra/newview/skins/default/xui/fr/floater_tools.xml b/indra/newview/skins/default/xui/fr/floater_tools.xml index 9597d38dca..c161f3f530 100644 --- a/indra/newview/skins/default/xui/fr/floater_tools.xml +++ b/indra/newview/skins/default/xui/fr/floater_tools.xml @@ -40,7 +40,7 @@  		Cliquez et faites glisser pour sélectionner le terrain.  	</floater.string>  	<floater.string name="status_selectcount"> -		[OBJ_COUNT] objets sélectionnés, impact sur le terrain [LAND_IMPACT] +		[OBJ_COUNT] objets sélectionnés, impact sur le terrain [LAND_IMPACT] [secondlife:///app/openfloater/object_weights ?]  	</floater.string>  	<floater.string name="status_remaining_capacity">  		Capacité restante [LAND_CAPACITY]. diff --git a/indra/newview/skins/default/xui/it/floater_tools.xml b/indra/newview/skins/default/xui/it/floater_tools.xml index a21ae9a485..f98a2da277 100644 --- a/indra/newview/skins/default/xui/it/floater_tools.xml +++ b/indra/newview/skins/default/xui/it/floater_tools.xml @@ -40,7 +40,7 @@  		Clicca e trascina per selezionare il terreno  	</floater.string>  	<floater.string name="status_selectcount"> -		[OBJ_COUNT] oggetti selezionati, impatto terreno [LAND_IMPACT] +		[OBJ_COUNT] oggetti selezionati, impatto terreno [LAND_IMPACT] [secondlife:///app/openfloater/object_weights ?]  	</floater.string>  	<floater.string name="status_remaining_capacity">  		Capacità restante [LAND_CAPACITY]. diff --git a/indra/newview/skins/default/xui/ja/floater_tools.xml b/indra/newview/skins/default/xui/ja/floater_tools.xml index aec0dbdb55..13f766698e 100644 --- a/indra/newview/skins/default/xui/ja/floater_tools.xml +++ b/indra/newview/skins/default/xui/ja/floater_tools.xml @@ -40,7 +40,7 @@  		土地をクリックし、ドラッグして選択  	</floater.string>  	<floater.string name="status_selectcount"> -		選択されているオブジェクトは [OBJ_COUNT] 個、土地の負荷は [LAND_IMPACT] +		選択されているオブジェクトは [OBJ_COUNT] 個、土地の負荷は [LAND_IMPACT] [secondlife:///app/openfloater/object_weights 詳細]  	</floater.string>  	<floater.string name="status_remaining_capacity">  		残りの許容数 [LAND_CAPACITY]。 diff --git a/indra/newview/skins/default/xui/pl/floater_tools.xml b/indra/newview/skins/default/xui/pl/floater_tools.xml index 5e2ed4a351..8932a86fd1 100644 --- a/indra/newview/skins/default/xui/pl/floater_tools.xml +++ b/indra/newview/skins/default/xui/pl/floater_tools.xml @@ -40,7 +40,7 @@  		Kliknij i przeciągnij, aby zaznaczyć teren  	</floater.string>  	<floater.string name="status_selectcount"> -		[OBJ_COUNT] zaznaczonych obiektów, wpływ na strefę: [LAND_IMPACT] +		[OBJ_COUNT] zaznaczonych obiektów, wpływ na strefę: [LAND_IMPACT] [secondlife:///app/openfloater/object_weights ?]  	</floater.string>  	<floater.string name="status_remaining_capacity">  		Pojemność pozostała: [LAND_CAPACITY]. diff --git a/indra/newview/skins/default/xui/pt/floater_tools.xml b/indra/newview/skins/default/xui/pt/floater_tools.xml index 0882f485a6..c0eab171c8 100644 --- a/indra/newview/skins/default/xui/pt/floater_tools.xml +++ b/indra/newview/skins/default/xui/pt/floater_tools.xml @@ -40,7 +40,7 @@  		Clicar e arrastar para selecionar a terra  	</floater.string>  	<floater.string name="status_selectcount"> -		[OBJ_COUNT] objetos selecionados, impacto no terreno [LAND_IMPACT] +		[OBJ_COUNT] objetos selecionados, impacto no terreno [LAND_IMPACT] [secondlife:///app/openfloater/object_weights ?]  	</floater.string>  	<floater.string name="status_remaining_capacity">  		Capacidade restante [LAND_CAPACITY]. diff --git a/indra/newview/skins/default/xui/ru/floater_tools.xml b/indra/newview/skins/default/xui/ru/floater_tools.xml index 82ee3c49ae..44f54aabb6 100644 --- a/indra/newview/skins/default/xui/ru/floater_tools.xml +++ b/indra/newview/skins/default/xui/ru/floater_tools.xml @@ -40,7 +40,7 @@  		Щелкните и перетащите для выделения земли  	</floater.string>  	<floater.string name="status_selectcount"> -		Выбрано объектов: [OBJ_COUNT], влияние на землю [LAND_IMPACT] +		Выбрано объектов: [OBJ_COUNT], влияние на землю [LAND_IMPACT] [secondlife:///app/openfloater/object_weights ?]  	</floater.string>  	<floater.string name="status_remaining_capacity">  		Остаток емкости [LAND_CAPACITY]. diff --git a/indra/newview/skins/default/xui/tr/floater_tools.xml b/indra/newview/skins/default/xui/tr/floater_tools.xml index d6b9a4a533..d48a617e38 100644 --- a/indra/newview/skins/default/xui/tr/floater_tools.xml +++ b/indra/newview/skins/default/xui/tr/floater_tools.xml @@ -40,7 +40,7 @@  		Araziyi seçmek için tıklayın ve sürükleyin  	</floater.string>  	<floater.string name="status_selectcount"> -		[OBJ_COUNT] nesne seçili, [LAND_IMPACT] arazi etkisi +		[OBJ_COUNT] nesne seçili, [LAND_IMPACT] arazi etkisi [secondlife:///app/openfloater/object_weights Ek bilgi]  	</floater.string>  	<floater.string name="status_remaining_capacity">  		Kalan kapasite [LAND_CAPACITY]. diff --git a/indra/newview/skins/default/xui/zh/floater_tools.xml b/indra/newview/skins/default/xui/zh/floater_tools.xml index 539c7454f1..f83b058ce1 100644 --- a/indra/newview/skins/default/xui/zh/floater_tools.xml +++ b/indra/newview/skins/default/xui/zh/floater_tools.xml @@ -40,7 +40,7 @@  		按住並拖曳,可以選取土地  	</floater.string>  	<floater.string name="status_selectcount"> -		選取了 [OBJ_COUNT] 個物件,土地衝擊量 [LAND_IMPACT] +		選取了 [OBJ_COUNT] 個物件,土地衝擊量 [LAND_IMPACT] [secondlife:///app/openfloater/object_weights 詳情]  	</floater.string>  	<floater.string name="status_remaining_capacity">  		剩餘容納量 [LAND_CAPACITY]。 diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index be5c9bfcc5..89481add29 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -518,7 +518,7 @@ class WindowsManifest(ViewerManifest):                  self.path("alut.dll")              # For textures -            self.path("openjpeg.dll") +            self.path("openjp2.dll")              # Uriparser              self.path("uriparser.dll") @@ -1501,7 +1501,7 @@ class Linux_i686_Manifest(LinuxManifest):              self.path("libdirectfb-1.*.so.*")              self.path("libfusion-1.*.so.*")              self.path("libdirect-1.*.so.*") -            self.path("libopenjpeg.so*") +            self.path("libopenjp2.so*")              self.path("libdirectfb-1.4.so.5")              self.path("libfusion-1.4.so.5")              self.path("libdirect-1.4.so.5*")  | 
