summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErik Kundiman <erik@megapahit.org>2025-08-08 07:30:46 +0800
committerErik Kundiman <erik@megapahit.org>2025-08-08 07:37:27 +0800
commitcfc4f075a82f9dc1156fce6994083143de6727a8 (patch)
tree2948ea5c6ebfbbc15721a2838804d6a766742887
parent73fdef6693017f1160875d1f7a79875945df3929 (diff)
parent55f1c8b9797836c9816528bb5b772eb83b083b50 (diff)
Merge tag 'Second_Life_Release#55f1c8b9-2025.06' into 2025.06
-rw-r--r--.github/pull_request_template.md1
-rw-r--r--.github/workflows/qatest.yaml49
-rw-r--r--CONTRIBUTING.md11
-rw-r--r--autobuild.xml58
-rw-r--r--indra/cmake/Copy3rdPartyLibs.cmake11
-rw-r--r--indra/cmake/Discord.cmake19
-rw-r--r--indra/llinventory/llinventory.cpp60
-rw-r--r--indra/llinventory/llinventory.h3
-rw-r--r--indra/llinventory/llpermissions.cpp104
-rw-r--r--indra/llinventory/llpermissions.h2
-rw-r--r--indra/llinventory/tests/inventorymisc_test.cpp2
-rw-r--r--indra/llmath/llvolume.cpp10
-rw-r--r--indra/llui/llfolderviewmodel.h67
-rw-r--r--indra/llui/lltextbase.cpp1
-rw-r--r--indra/llui/llurlaction.cpp28
-rw-r--r--indra/llui/llurlaction.h4
-rw-r--r--indra/llui/llurlentry.cpp18
-rw-r--r--indra/llui/llurlentry.h6
-rw-r--r--indra/llwebrtc/llwebrtc.cpp56
-rw-r--r--indra/llwebrtc/llwebrtc_impl.h7
-rw-r--r--indra/llwindow/llwindowwin32.cpp101
-rw-r--r--indra/llwindow/llwindowwin32.h7
-rw-r--r--indra/newview/CMakeLists.txt16
-rw-r--r--indra/newview/app_settings/settings.xml63
-rw-r--r--indra/newview/llagentwearables.cpp10
-rw-r--r--indra/newview/llappearancemgr.cpp2
-rw-r--r--indra/newview/llappviewer.cpp12
-rw-r--r--indra/newview/llappviewerwin32.cpp1
-rw-r--r--indra/newview/llconversationmodel.cpp20
-rw-r--r--indra/newview/llfloaterchatmentionpicker.cpp2
-rw-r--r--indra/newview/llfloaterimagepreview.cpp114
-rw-r--r--indra/newview/llfloaterimagepreview.h2
-rw-r--r--indra/newview/llfloaterimcontainer.cpp6
-rw-r--r--indra/newview/llfloaterimsessiontab.cpp45
-rw-r--r--indra/newview/llfloatermediasettings.cpp9
-rw-r--r--indra/newview/llfloatermediasettings.h2
-rw-r--r--indra/newview/llfloatermodelpreview.cpp6
-rw-r--r--indra/newview/llfloatermodelpreview.h2
-rw-r--r--indra/newview/llfloaterpreference.cpp4
-rw-r--r--indra/newview/llfloatersettingsdebug.cpp5
-rw-r--r--indra/newview/llfloatersettingsdebug.h1
-rwxr-xr-xindra/newview/llfloaterworldmap.cpp46
-rw-r--r--indra/newview/llhudeffectlookat.cpp39
-rw-r--r--indra/newview/llhudeffectpointat.cpp14
-rw-r--r--indra/newview/llimprocessing.cpp4
-rw-r--r--indra/newview/llinventorybridge.cpp24
-rw-r--r--indra/newview/llinventorybridge.h1
-rw-r--r--indra/newview/llinventoryfunctions.cpp10
-rw-r--r--indra/newview/llinventorymodel.cpp172
-rw-r--r--indra/newview/lllogchat.cpp33
-rw-r--r--indra/newview/llmeshrepository.cpp10
-rw-r--r--indra/newview/llmutelist.cpp50
-rw-r--r--indra/newview/llmutelist.h14
-rw-r--r--indra/newview/lloutfitslist.cpp24
-rw-r--r--indra/newview/llpanelemojicomplete.cpp1
-rw-r--r--indra/newview/llpanelface.cpp17
-rw-r--r--indra/newview/llpanellogin.cpp103
-rw-r--r--indra/newview/llpanellogin.h1
-rw-r--r--indra/newview/llpanelpeople.cpp2
-rw-r--r--indra/newview/llpanelpeoplemenus.cpp6
-rw-r--r--indra/newview/llselectmgr.cpp22
-rw-r--r--indra/newview/llspeakers.cpp2
-rw-r--r--indra/newview/llstatusbar.cpp62
-rw-r--r--indra/newview/llstatusbar.h12
-rw-r--r--indra/newview/lltooldraganddrop.cpp13
-rw-r--r--indra/newview/llviewerinventory.cpp19
-rw-r--r--indra/newview/llviewerinventory.h2
-rw-r--r--indra/newview/llviewermedia_streamingaudio.cpp21
-rw-r--r--indra/newview/llviewermenufile.cpp161
-rw-r--r--indra/newview/llviewermessage.cpp16
-rw-r--r--indra/newview/llvoavatar.cpp76
-rw-r--r--indra/newview/llvoavatar.h5
-rw-r--r--indra/newview/llvoavatarself.cpp14
-rw-r--r--indra/newview/llvoavatarself.h2
-rw-r--r--indra/newview/llvoicewebrtc.cpp42
-rw-r--r--indra/newview/res/ll_icon_small.icobin0 -> 91010 bytes
-rw-r--r--indra/newview/res/resource.h1
-rwxr-xr-xindra/newview/res/viewerRes.rc1
-rw-r--r--indra/newview/skins/default/textures/textures.xml1
-rw-r--r--indra/newview/skins/default/textures/windows/first_login_image.jpgbin199811 -> 0 bytes
-rw-r--r--indra/newview/skins/default/xui/de/panel_login_first.xml39
-rw-r--r--indra/newview/skins/default/xui/en/floater_test_slapp.xml10
-rw-r--r--indra/newview/skins/default/xui/en/menu_url_parcel.xml2
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml11
-rw-r--r--indra/newview/skins/default/xui/en/panel_login_first.xml262
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_advanced.xml10
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_privacy.xml33
-rw-r--r--indra/newview/skins/default/xui/en/panel_status_bar.xml2
-rw-r--r--indra/newview/skins/default/xui/es/panel_login_first.xml39
-rw-r--r--indra/newview/skins/default/xui/fr/panel_login_first.xml39
-rw-r--r--indra/newview/skins/default/xui/it/panel_login_first.xml39
-rw-r--r--indra/newview/skins/default/xui/ja/panel_login_first.xml54
-rw-r--r--indra/newview/skins/default/xui/pl/panel_login_first.xml30
-rw-r--r--indra/newview/skins/default/xui/pt/panel_login_first.xml39
-rw-r--r--indra/newview/skins/default/xui/ru/panel_login_first.xml39
-rw-r--r--indra/newview/skins/default/xui/tr/panel_login_first.xml39
-rw-r--r--indra/newview/skins/default/xui/zh/panel_login_first.xml39
-rw-r--r--indra/newview/tests/llviewerassetstats_test.cpp5
-rwxr-xr-xindra/newview/viewer_manifest.py12
99 files changed, 1539 insertions, 1194 deletions
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 473498833e..5fe8870337 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -19,6 +19,7 @@ Issue Link: <!-- e.g., closes #123 or relates to #456 -->
Please ensure the following before requesting review:
- [ ] I have provided a clear title and detailed description for this pull request.
+- [ ] If useful, I have included media such as screenshots and video to show off my changes.
- [ ] The PR is linked to a relevant issue with sufficient context.
- [ ] I have tested the changes locally and verified they work as intended.
- [ ] All new and existing tests pass.
diff --git a/.github/workflows/qatest.yaml b/.github/workflows/qatest.yaml
index 5d8894a3f4..4e10900441 100644
--- a/.github/workflows/qatest.yaml
+++ b/.github/workflows/qatest.yaml
@@ -46,11 +46,10 @@ jobs:
runner: qa-dan-asus
artifact: Windows-installer
install-path: 'C:\viewer-automation-main'
- # Commented out until mac runner is available
- # - os: mac
- # runner: qa-mac-atlas
- # artifact: Mac-installer
- # install-path: '$HOME/Documents/viewer-automation'
+ - os: mac
+ runner: qa-mac-atlas
+ artifact: macOS-installer
+ install-path: '$HOME/Documents/viewer-automation'
fail-fast: false
runs-on: [self-hosted, "${{ matrix.runner }}"]
@@ -498,11 +497,13 @@ jobs:
mkdir -p "$MOUNT_POINT"
# Mount the DMG
- hdiutil attach "${{ env.INSTALLER_PATH }}" -mountpoint "$MOUNT_POINT" -nobrowse
+ hdiutil attach "$INSTALLER_PATH" -mountpoint "$MOUNT_POINT" -nobrowse
echo "✅ DMG mounted at $MOUNT_POINT"
- # Find the app in the mounted DMG
+ echo "Installing application to default location from DMG..."
+
+ # Find the .app bundle in the DMG
APP_PATH=$(find "$MOUNT_POINT" -name "*.app" -type d | head -1)
if [ -z "$APP_PATH" ]; then
@@ -510,18 +511,40 @@ jobs:
exit 1
fi
- echo "Installing application to Applications folder..."
+ APP_NAME=$(basename "$APP_PATH")
+ DEST_PATH="/Applications/$APP_NAME"
+
+ # Handle existing installation
+ if [ -d "$DEST_PATH" ]; then
+ echo "Found existing installation at: $DEST_PATH"
+ echo "Moving existing installation to trash..."
+
+ # Move to trash instead of force removing
+ TRASH_PATH="$HOME/.Trash/$(date +%Y%m%d_%H%M%S)_$APP_NAME"
+ mv "$DEST_PATH" "$TRASH_PATH" || {
+ echo "⚠️ Could not move to trash, trying direct removal..."
+ rm -rf "$DEST_PATH" || {
+ echo "❌ Could not remove existing installation"
+ echo "Please manually remove: $DEST_PATH"
+ exit 1
+ }
+ }
+
+ echo "✅ Existing installation handled successfully"
+ fi
- # Copy the app to the Applications folder (or specified install path)
- cp -R "$APP_PATH" "${{ matrix.install-path }}"
+ # Copy the .app to /Applications
+ echo "Copying app from: $APP_PATH"
+ echo "To destination: /Applications/"
+ cp -R "$APP_PATH" /Applications/
# Verify the app was copied successfully
- if [ ! -d "${{ matrix.install-path }}/$(basename "$APP_PATH")" ]; then
- echo "❌ Error: Failed to install application to ${{ matrix.install-path }}!"
+ if [ ! -d "$DEST_PATH" ]; then
+ echo "❌ Error: Failed to install application to /Applications!"
exit 1
fi
- echo "✅ Application installed successfully to ${{ matrix.install-path }}"
+ echo "✅ Application installed successfully to /Applications"
# Save mount point for cleanup
echo "MOUNT_POINT=$MOUNT_POINT" >> $GITHUB_ENV
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d75a765a61..0771e6a6e6 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -8,6 +8,7 @@ changes.
## Table of contents
- [Communication](#communication)
+- [What to work on](#what-to-work-on)
- [Reporting bugs and requesting features](#reporting-bugs-and-requesting-features)
- [Contributing pull requests](#contributing-pull-requests)
@@ -34,6 +35,16 @@ developer-to-developer or support.
discussion between viewer maintainers.
- Our [Discord][] is available for real-time discussion.
+## What to work on
+
+If you're looking for ways to contribute code, here are some ways to get involved:
+
+- Explore existing issues on the [GitHub issue tracker](https://github.com/secondlife/viewer/issues) to find known problems, bugs, or enhancement discussions.
+- File new issues if you’ve discovered a bug or have a specific idea to propose. If your idea is user-facing, consider submitting it through feedback.secondlife.com so it can reach a broader audience and be prioritized by Linden Lab staff.
+- Look for the [help wanted](https://github.com/secondlife/viewer/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22help%20wanted%22) label. These are tasks the core maintainers have specifically identified as good candidates for community help.
+- Talk to maintainers before starting significant work. Even if an issue exists, discussing your approach first ensures alignment with ongoing efforts and increases the likelihood your pull request will be accepted.
+
+Collaboration is essential. We encourage contributors to work closely with the Second Life engineering team and other developers to keep work consistent and maintainable.
## Reporting bugs and requesting features
diff --git a/autobuild.xml b/autobuild.xml
index ff1c9414a3..349f6e34a3 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -2885,6 +2885,64 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>version</key>
<string>1.0.9-5e8947c</string>
</map>
+ <key>discord_sdk</key>
+ <map>
+ <key>platforms</key>
+ <map>
+ <key>windows64</key>
+ <map>
+ <key>archive</key>
+ <map>
+ <key>creds</key>
+ <string>github</string>
+ <key>hash</key>
+ <string>e11571bf76b27d15c244069988ae372eaa5afae9</string>
+ <key>hash_algorithm</key>
+ <string>sha1</string>
+ <key>url</key>
+ <string>https://api.github.com/repos/secondlife/3p-discord-sdk/releases/assets/279333720</string>
+ </map>
+ <key>name</key>
+ <string>windows64</string>
+ </map>
+ <key>darwin64</key>
+ <map>
+ <key>archive</key>
+ <map>
+ <key>creds</key>
+ <string>github</string>
+ <key>hash</key>
+ <string>dc21df8b051c425163acf3eff8f06e32f407c9e0</string>
+ <key>hash_algorithm</key>
+ <string>sha1</string>
+ <key>url</key>
+ <string>https://api.github.com/repos/secondlife/3p-discord-sdk/releases/assets/279333706</string>
+ </map>
+ <key>name</key>
+ <string>darwin64</string>
+ </map>
+ </map>
+ <key>license</key>
+ <string>discord_sdk</string>
+ <key>license_file</key>
+ <string>LICENSES/discord_sdk.txt</string>
+ <key>copyright</key>
+ <string>Discord Inc.</string>
+ <key>version</key>
+ <string>1.4.9649.16733550144</string>
+ <key>name</key>
+ <string>discord_sdk</string>
+ <key>vcs_branch</key>
+ <string>main</string>
+ <key>vcs_revision</key>
+ <string>ef5c7c4a490ceac2df2b2f046788b1daf1bbb392</string>
+ <key>vcs_url</key>
+ <string>https://github.com/secondlife/3p-discord-sdk</string>
+ <key>canonical_repo</key>
+ <string>https://github.com/secondlife/3p-discord-sdk</string>
+ <key>description</key>
+ <string>Discord Social SDK</string>
+ </map>
</map>
<key>package_description</key>
<map>
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index 6ac00fd131..0153e69d5b 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -6,6 +6,9 @@
include(CMakeCopyIfDifferent)
include(Linking)
+if (USE_DISCORD)
+ include(Discord)
+endif ()
include(OPENAL)
# When we copy our dependent libraries, we almost always want to copy them to
@@ -75,6 +78,10 @@ if(WINDOWS)
endif(ADDRESS_SIZE EQUAL 32)
endif (USE_BUGSPLAT)
+ if (TARGET ll::discord_sdk)
+ list(APPEND release_files discord_partner_sdk.dll)
+ endif ()
+
if (TARGET ll::openal)
list(APPEND release_files openal32.dll alut.dll)
endif ()
@@ -180,6 +187,10 @@ elseif(DARWIN)
)
endif()
+ if (TARGET ll::discord_sdk)
+ list(APPEND release_files libdiscord_partner_sdk.dylib)
+ endif ()
+
if (TARGET ll::openal)
list(APPEND release_files libalut.dylib libopenal.dylib)
endif ()
diff --git a/indra/cmake/Discord.cmake b/indra/cmake/Discord.cmake
index 52c0765ae7..1896c12853 100644
--- a/indra/cmake/Discord.cmake
+++ b/indra/cmake/Discord.cmake
@@ -1,18 +1,23 @@
include(Prebuilt)
-add_library(ll::discord INTERFACE IMPORTED)
-target_compile_definitions(ll::discord INTERFACE LL_DISCORD=1)
+include_guard()
-if (${PREBUILD_TRACKING_DIR}/sentinel_installed IS_NEWER_THAN ${PREBUILD_TRACKING_DIR}/discord_installed OR NOT ${discord_installed} EQUAL 0)
+add_library(ll::discord_sdk INTERFACE IMPORTED)
+target_compile_definitions(ll::discord_sdk INTERFACE LL_DISCORD=1)
+
+#use_prebuilt_binary(discord_sdk)
+
+if (${PREBUILD_TRACKING_DIR}/sentinel_installed IS_NEWER_THAN ${PREBUILD_TRACKING_DIR}/discord_sdk_installed OR NOT ${discord_sdk_installed} EQUAL 0)
file(ARCHIVE_EXTRACT
INPUT $ENV{HOME}/Downloads/DiscordSocialSdk-1.4.9649.zip
DESTINATION ${CMAKE_BINARY_DIR}
)
+ file(MAKE_DIRECTORY ${LIBS_PREBUILT_DIR}/include/discord_sdk)
file(
COPY
${CMAKE_BINARY_DIR}/discord_social_sdk/include/cdiscord.h
${CMAKE_BINARY_DIR}/discord_social_sdk/include/discordpp.h
- DESTINATION ${LIBS_PREBUILT_DIR}/include
+ DESTINATION ${LIBS_PREBUILT_DIR}/include/discord_sdk
)
if (WINDOWS)
file(
@@ -38,8 +43,8 @@ if (${PREBUILD_TRACKING_DIR}/sentinel_installed IS_NEWER_THAN ${PREBUILD_TRACKIN
DESTINATION ${ARCH_PREBUILT_DIRS_RELEASE}
)
endif ()
- file(WRITE ${PREBUILD_TRACKING_DIR}/discord_installed "0")
+ file(WRITE ${PREBUILD_TRACKING_DIR}/discord_sdk_installed "0")
endif ()
-target_include_directories(ll::discord SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include)
-target_link_libraries(ll::discord INTERFACE discord_partner_sdk)
+target_include_directories(ll::discord_sdk SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/discord_sdk)
+target_link_libraries(ll::discord_sdk INTERFACE discord_partner_sdk)
diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp
index fe60800700..3defad8f3b 100644
--- a/indra/llinventory/llinventory.cpp
+++ b/indra/llinventory/llinventory.cpp
@@ -995,6 +995,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
// TODO - figure out if this should be moved into the noclobber fields above
mThumbnailUUID.setNull();
mFavorite = false;
+ mPermissions.init(LLUUID::null, LLUUID::null, LLUUID::null, LLUUID::null);
// iterate as map to avoid making unnecessary temp copies of everything
LLSD::map_const_iterator i, end;
@@ -1053,7 +1054,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)
if (i->first == INV_PERMISSIONS_LABEL)
{
- mPermissions = ll_permissions_from_sd(i->second);
+ mPermissions.importLLSD(i->second);
continue;
}
@@ -1522,53 +1523,68 @@ void LLInventoryCategory::exportLLSD(LLSD& cat_data) const
}
}
-bool LLInventoryCategory::importLLSD(const LLSD& cat_data)
+bool LLInventoryCategory::importLLSDMap(const LLSD& cat_data)
{
- if (cat_data.has(INV_FOLDER_ID_LABEL))
+ LLSD::map_const_iterator i, end;
+ end = cat_data.endMap();
+ for ( i = cat_data.beginMap(); i != end; ++i)
+ {
+ importLLSD(i->first, i->second);
+ }
+ return true;
+}
+
+bool LLInventoryCategory::importLLSD(const std::string& label, const LLSD& value)
+{
+ if (label == INV_FOLDER_ID_LABEL)
{
- setUUID(cat_data[INV_FOLDER_ID_LABEL].asUUID());
+ setUUID(value.asUUID());
+ return true;
}
- if (cat_data.has(INV_PARENT_ID_LABEL))
+ else if (label == INV_PARENT_ID_LABEL)
{
- setParent(cat_data[INV_PARENT_ID_LABEL].asUUID());
+ setParent(value.asUUID());
+ return true;
}
- if (cat_data.has(INV_ASSET_TYPE_LABEL))
+ else if (label == INV_ASSET_TYPE_LABEL)
{
- setType(LLAssetType::lookup(cat_data[INV_ASSET_TYPE_LABEL].asString()));
+ setType(LLAssetType::lookup(value.asString()));
+ return true;
}
- if (cat_data.has(INV_PREFERRED_TYPE_LABEL))
+ else if (label == INV_PREFERRED_TYPE_LABEL)
{
- setPreferredType(LLFolderType::lookup(cat_data[INV_PREFERRED_TYPE_LABEL].asString()));
+ setPreferredType(LLFolderType::lookup(value.asString()));
+ return true;
}
- if (cat_data.has(INV_THUMBNAIL_LABEL))
+ else if (label == INV_THUMBNAIL_LABEL)
{
LLUUID thumbnail_uuid;
- const LLSD &thumbnail_data = cat_data[INV_THUMBNAIL_LABEL];
- if (thumbnail_data.has(INV_ASSET_ID_LABEL))
+ if (value.has(INV_ASSET_ID_LABEL))
{
- thumbnail_uuid = thumbnail_data[INV_ASSET_ID_LABEL].asUUID();
+ thumbnail_uuid = value[INV_ASSET_ID_LABEL].asUUID();
}
setThumbnailUUID(thumbnail_uuid);
+ return true;
}
- if (cat_data.has(INV_FAVORITE_LABEL))
+ if (label == INV_FAVORITE_LABEL)
{
bool favorite = false;
- const LLSD& favorite_data = cat_data[INV_FAVORITE_LABEL];
- if (favorite_data.has(INV_TOGGLED_LABEL))
+ if (value.has(INV_TOGGLED_LABEL))
{
- favorite = favorite_data[INV_TOGGLED_LABEL].asBoolean();
+ favorite = value[INV_TOGGLED_LABEL].asBoolean();
}
setFavorite(favorite);
}
- if (cat_data.has(INV_NAME_LABEL))
+ else if (label == INV_NAME_LABEL)
{
- mName = cat_data[INV_NAME_LABEL].asString();
+ mName = value.asString();
LLStringUtil::replaceNonstandardASCII(mName, ' ');
LLStringUtil::replaceChar(mName, '|', ' ');
+ return true;
}
-
- return true;
+ return false;
}
+
///----------------------------------------------------------------------------
/// Local function definitions for testing purposes
///----------------------------------------------------------------------------
diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h
index 17670d2ea1..181c46226c 100644
--- a/indra/llinventory/llinventory.h
+++ b/indra/llinventory/llinventory.h
@@ -274,7 +274,8 @@ public:
virtual bool exportLegacyStream(std::ostream& output_stream, bool include_asset_key = true) const;
virtual void exportLLSD(LLSD& sd) const;
- bool importLLSD(const LLSD& cat_data);
+ bool importLLSDMap(const LLSD& cat_data);
+ virtual bool importLLSD(const std::string& label, const LLSD& value);
//--------------------------------------------------------------------
// Member Variables
//--------------------------------------------------------------------
diff --git a/indra/llinventory/llpermissions.cpp b/indra/llinventory/llpermissions.cpp
index d800ca02c9..ebf7445c65 100644
--- a/indra/llinventory/llpermissions.cpp
+++ b/indra/llinventory/llpermissions.cpp
@@ -704,6 +704,79 @@ bool LLPermissions::exportLegacyStream(std::ostream& output_stream) const
return true;
}
+static const std::string PERM_CREATOR_ID_LABEL("creator_id");
+static const std::string PERM_OWNER_ID_LABEL("owner_id");
+static const std::string PERM_LAST_OWNER_ID_LABEL("last_owner_id");
+static const std::string PERM_GROUP_ID_LABEL("group_id");
+static const std::string PERM_IS_OWNER_GROUP_LABEL("is_owner_group");
+static const std::string PERM_BASE_MASK_LABEL("base_mask");
+static const std::string PERM_OWNER_MASK_LABEL("owner_mask");
+static const std::string PERM_GROUP_MASK_LABEL("group_mask");
+static const std::string PERM_EVERYONE_MASK_LABEL("everyone_mask");
+static const std::string PERM_NEXT_OWNER_MASK_LABEL("next_owner_mask");
+
+void LLPermissions::importLLSD(const LLSD& sd_perm)
+{
+ LLSD::map_const_iterator i, end;
+ end = sd_perm.endMap();
+ for (i = sd_perm.beginMap(); i != end; ++i)
+ {
+ const std::string& label = i->first;
+ if (label == PERM_CREATOR_ID_LABEL)
+ {
+ mCreator = i->second.asUUID();
+ continue;
+ }
+ if (label == PERM_OWNER_ID_LABEL)
+ {
+ mOwner = i->second.asUUID();
+ continue;
+ }
+ if (label == PERM_LAST_OWNER_ID_LABEL)
+ {
+ mLastOwner = i->second.asUUID();
+ continue;
+ }
+ if (label == PERM_GROUP_ID_LABEL)
+ {
+ mGroup = i->second.asUUID();
+ continue;
+ }
+ if (label == PERM_BASE_MASK_LABEL)
+ {
+ PermissionMask mask = i->second.asInteger();
+ mMaskBase = mask;
+ continue;
+ }
+ if (label == PERM_OWNER_MASK_LABEL)
+ {
+ PermissionMask mask = i->second.asInteger();
+ mMaskOwner = mask;
+ continue;
+ }
+ if (label == PERM_EVERYONE_MASK_LABEL)
+ {
+ PermissionMask mask = i->second.asInteger();
+ mMaskEveryone = mask;
+ continue;
+ }
+ if (label == PERM_GROUP_MASK_LABEL)
+ {
+ PermissionMask mask = i->second.asInteger();
+ mMaskGroup = mask;
+ continue;
+ }
+ if (label == PERM_NEXT_OWNER_MASK_LABEL)
+ {
+ PermissionMask mask = i->second.asInteger();
+ mMaskNextOwner = mask;
+ continue;
+ }
+ }
+
+ fix();
+}
+
bool LLPermissions::operator==(const LLPermissions &rhs) const
{
return
@@ -998,16 +1071,6 @@ std::string mask_to_string(U32 mask)
///----------------------------------------------------------------------------
/// exported functions
///----------------------------------------------------------------------------
-static const std::string PERM_CREATOR_ID_LABEL("creator_id");
-static const std::string PERM_OWNER_ID_LABEL("owner_id");
-static const std::string PERM_LAST_OWNER_ID_LABEL("last_owner_id");
-static const std::string PERM_GROUP_ID_LABEL("group_id");
-static const std::string PERM_IS_OWNER_GROUP_LABEL("is_owner_group");
-static const std::string PERM_BASE_MASK_LABEL("base_mask");
-static const std::string PERM_OWNER_MASK_LABEL("owner_mask");
-static const std::string PERM_GROUP_MASK_LABEL("group_mask");
-static const std::string PERM_EVERYONE_MASK_LABEL("everyone_mask");
-static const std::string PERM_NEXT_OWNER_MASK_LABEL("next_owner_mask");
LLSD ll_create_sd_from_permissions(const LLPermissions& perm)
{
@@ -1032,25 +1095,6 @@ void ll_fill_sd_from_permissions(LLSD& rv, const LLPermissions& perm)
LLPermissions ll_permissions_from_sd(const LLSD& sd_perm)
{
LLPermissions rv;
- rv.init(
- sd_perm[PERM_CREATOR_ID_LABEL].asUUID(),
- sd_perm[PERM_OWNER_ID_LABEL].asUUID(),
- sd_perm[PERM_LAST_OWNER_ID_LABEL].asUUID(),
- sd_perm[PERM_GROUP_ID_LABEL].asUUID());
-
- // We do a cast to U32 here since LLSD does not attempt to
- // represent unsigned ints.
- PermissionMask mask;
- mask = (U32)(sd_perm[PERM_BASE_MASK_LABEL].asInteger());
- rv.setMaskBase(mask);
- mask = (U32)(sd_perm[PERM_OWNER_MASK_LABEL].asInteger());
- rv.setMaskOwner(mask);
- mask = (U32)(sd_perm[PERM_EVERYONE_MASK_LABEL].asInteger());
- rv.setMaskEveryone(mask);
- mask = (U32)(sd_perm[PERM_GROUP_MASK_LABEL].asInteger());
- rv.setMaskGroup(mask);
- mask = (U32)(sd_perm[PERM_NEXT_OWNER_MASK_LABEL].asInteger());
- rv.setMaskNext(mask);
- rv.fix();
+ rv.importLLSD(sd_perm);
return rv;
}
diff --git a/indra/llinventory/llpermissions.h b/indra/llinventory/llpermissions.h
index f3e10af25c..82cdc03727 100644
--- a/indra/llinventory/llpermissions.h
+++ b/indra/llinventory/llpermissions.h
@@ -299,6 +299,8 @@ public:
bool importLegacyStream(std::istream& input_stream);
bool exportLegacyStream(std::ostream& output_stream) const;
+ void importLLSD(const LLSD& sd_perm);
+
bool operator==(const LLPermissions &rhs) const;
bool operator!=(const LLPermissions &rhs) const;
diff --git a/indra/llinventory/tests/inventorymisc_test.cpp b/indra/llinventory/tests/inventorymisc_test.cpp
index e41500b4c5..f11a4c3bf7 100644
--- a/indra/llinventory/tests/inventorymisc_test.cpp
+++ b/indra/llinventory/tests/inventorymisc_test.cpp
@@ -518,7 +518,7 @@ namespace tut
file.close();
LLPointer<LLInventoryCategory> src2 = new LLInventoryCategory();
- src2->importLLSD(s_item);
+ src2->importLLSDMap(s_item);
ensure_equals("1.item id::getUUID() failed", src1->getUUID(), src2->getUUID());
ensure_equals("2.parent::getParentUUID() failed", src1->getParentUUID(), src2->getParentUUID());
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index d56891cab3..e5521e0ffc 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -5711,7 +5711,15 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
S32 vert_count = 0;
if (!data.p.empty())
{
- vert_count = static_cast<S32>(meshopt_generateVertexRemapMulti(&remap[0], nullptr, data.p.size(), data.p.size(), mos, stream_count));
+ try
+ {
+ vert_count = static_cast<S32>(meshopt_generateVertexRemapMulti(&remap[0], nullptr, data.p.size(), data.p.size(), mos, stream_count));
+ }
+ catch (std::bad_alloc&)
+ {
+ LLError::LLUserWarningMsg::showOutOfMemory();
+ LL_ERRS("LLCoros") << "Failed to allocate memory for VertexRemap: " << (S32)data.p.size() << LL_ENDL;
+ }
}
if (vert_count < 65535 && vert_count != 0)
diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h
index ba9d0b8de3..2865b789b9 100644
--- a/indra/llui/llfolderviewmodel.h
+++ b/indra/llui/llfolderviewmodel.h
@@ -224,6 +224,7 @@ public:
virtual S32 getSortVersion() = 0;
virtual void setSortVersion(S32 version) = 0;
virtual void setParent(LLFolderViewModelItem* parent) = 0;
+ virtual const LLFolderViewModelItem* getParent() = 0;
virtual bool hasParent() = 0;
protected:
@@ -254,14 +255,14 @@ public:
mChildren.clear();
}
- void requestSort() { mSortVersion = -1; }
- S32 getSortVersion() { return mSortVersion; }
- void setSortVersion(S32 version) { mSortVersion = version;}
+ void requestSort() override { mSortVersion = -1; }
+ S32 getSortVersion() override { return mSortVersion; }
+ void setSortVersion(S32 version) override { mSortVersion = version;}
- S32 getLastFilterGeneration() const { return mLastFilterGeneration; }
+ S32 getLastFilterGeneration() const override { return mLastFilterGeneration; }
S32 getLastFolderFilterGeneration() const { return mLastFolderFilterGeneration; }
- S32 getMarkedDirtyGeneration() const { return mMarkedDirtyGeneration; }
- void dirtyFilter()
+ S32 getMarkedDirtyGeneration() const override { return mMarkedDirtyGeneration; }
+ void dirtyFilter() override
{
if(mMarkedDirtyGeneration < 0)
{
@@ -276,7 +277,7 @@ public:
mParent->dirtyFilter();
}
}
- void dirtyDescendantsFilter()
+ void dirtyDescendantsFilter() override
{
mMostFilteredDescendantGeneration = -1;
if (mParent)
@@ -284,13 +285,13 @@ public:
mParent->dirtyDescendantsFilter();
}
}
- bool hasFilterStringMatch();
- std::string::size_type getFilterStringOffset();
- std::string::size_type getFilterStringSize();
+ bool hasFilterStringMatch() override;
+ std::string::size_type getFilterStringOffset() override;
+ std::string::size_type getFilterStringSize() override;
- typedef std::list<LLFolderViewModelItem*> child_list_t;
+ typedef std::list<LLPointer<LLFolderViewModelItem> > child_list_t;
- virtual void addChild(LLFolderViewModelItem* child)
+ virtual void addChild(LLFolderViewModelItem* child) override
{
mChildren.push_back(child);
child->setParent(this);
@@ -298,15 +299,15 @@ public:
requestSort();
}
- virtual void removeChild(LLFolderViewModelItem* child)
+ virtual void removeChild(LLFolderViewModelItem* child) override final
{
- mChildren.remove(child);
child->setParent(NULL);
+ mChildren.remove(child);
dirtyDescendantsFilter();
dirtyFilter();
}
- virtual void clearChildren()
+ virtual void clearChildren() override
{
// We are working with models that belong to views as LLPointers, clean the list, let poiters handle the rest
std::for_each(mChildren.begin(), mChildren.end(), [](LLFolderViewModelItem* c) {c->setParent(NULL); });
@@ -319,7 +320,7 @@ public:
child_list_t::const_iterator getChildrenEnd() const { return mChildren.end(); }
child_list_t::size_type getChildrenCount() const { return mChildren.size(); }
- void setPassedFilter(bool passed, S32 filter_generation, std::string::size_type string_offset = std::string::npos, std::string::size_type string_size = 0)
+ void setPassedFilter(bool passed, S32 filter_generation, std::string::size_type string_offset = std::string::npos, std::string::size_type string_size = 0) override
{
mPassedFilter = passed;
mLastFilterGeneration = filter_generation;
@@ -328,20 +329,20 @@ public:
mMarkedDirtyGeneration = -1;
}
- void setPassedFolderFilter(bool passed, S32 filter_generation)
+ void setPassedFolderFilter(bool passed, S32 filter_generation) override
{
mPassedFolderFilter = passed;
mLastFolderFilterGeneration = filter_generation;
}
- virtual bool potentiallyVisible()
+ virtual bool potentiallyVisible() override
{
return passedFilter() // we've passed the filter
|| (getLastFilterGeneration() < mRootViewModel.getFilter().getFirstSuccessGeneration()) // or we don't know yet
|| descendantsPassedFilter();
}
- virtual bool passedFilter(S32 filter_generation = -1)
+ virtual bool passedFilter(S32 filter_generation = -1) override
{
if (filter_generation < 0)
{
@@ -352,7 +353,7 @@ public:
return passed_folder_filter && (passed_filter || descendantsPassedFilter(filter_generation));
}
- virtual bool descendantsPassedFilter(S32 filter_generation = -1)
+ virtual bool descendantsPassedFilter(S32 filter_generation = -1) override
{
if (filter_generation < 0)
{
@@ -361,10 +362,10 @@ public:
return mMostFilteredDescendantGeneration >= filter_generation;
}
-
protected:
- virtual void setParent(LLFolderViewModelItem* parent) { mParent = parent; }
- virtual bool hasParent() { return mParent != NULL; }
+ virtual void setParent(LLFolderViewModelItem* parent) override final { mParent = parent; }
+ virtual const LLFolderViewModelItem* getParent() override { return mParent; };
+ virtual bool hasParent() override { return mParent != NULL; }
S32 mSortVersion;
bool mPassedFilter;
@@ -381,7 +382,7 @@ protected:
LLFolderViewModelItem* mParent;
LLFolderViewModelInterface& mRootViewModel;
- void setFolderViewItem(LLFolderViewItem* folder_view_item) { mFolderViewItem = folder_view_item;}
+ void setFolderViewItem(LLFolderViewItem* folder_view_item) override { mFolderViewItem = folder_view_item;}
LLFolderViewItem* mFolderViewItem;
};
@@ -395,15 +396,15 @@ public:
mFolderView(NULL)
{}
- virtual void requestSortAll()
+ virtual void requestSortAll() override
{
// sort everything
mTargetSortVersion++;
}
- virtual std::string getStatusText(bool is_empty_folder = false);
- virtual void filter();
+ virtual std::string getStatusText(bool is_empty_folder = false) override;
+ virtual void filter() override;
- void setFolderView(LLFolderView* folder_view) { mFolderView = folder_view;}
+ void setFolderView(LLFolderView* folder_view) override { mFolderView = folder_view;}
protected:
bool needsSort(class LLFolderViewModelItem* item);
@@ -433,14 +434,14 @@ public:
virtual const SortType& getSorter() const { return *mSorter; }
virtual void setSorter(const SortType& sorter) { mSorter.reset(new SortType(sorter)); requestSortAll(); }
- virtual FilterType& getFilter() { return *mFilter; }
- virtual const FilterType& getFilter() const { return *mFilter; }
+ virtual FilterType& getFilter() override { return *mFilter; }
+ virtual const FilterType& getFilter() const override { return *mFilter; }
virtual void setFilter(const FilterType& filter) { mFilter.reset(new FilterType(filter)); }
// By default, we assume the content is available. If a network fetch mechanism is implemented for the model,
// this method needs to be overloaded and return the relevant fetch status.
- virtual bool contentsReady() { return true; }
- virtual bool isFolderComplete(LLFolderViewFolder* folder) { return true; }
+ virtual bool contentsReady() override { return true; }
+ virtual bool isFolderComplete(LLFolderViewFolder* folder) override { return true; }
struct ViewModelCompare
{
@@ -461,7 +462,7 @@ public:
const SortType& mSorter;
};
- void sort(LLFolderViewFolder* folder)
+ void sort(LLFolderViewFolder* folder) override
{
if (needsSort(folder->getViewModelItem()))
{
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 778b253c3c..7007049e1c 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -2228,6 +2228,7 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url)
registrar.add("Url.ReportAbuse", boost::bind(&LLUrlAction::reportAbuse, url));
registrar.add("Url.SendIM", boost::bind(&LLUrlAction::sendIM, url));
registrar.add("Url.ShowOnMap", boost::bind(&LLUrlAction::showLocationOnMap, url));
+ registrar.add("Url.ShowParcelOnMap", boost::bind(&LLUrlAction::showParcelOnMap, url));
registrar.add("Url.CopyLabel", boost::bind(&LLUrlAction::copyLabelToClipboard, url));
registrar.add("Url.CopyUrl", boost::bind(&LLUrlAction::copyURLToClipboard, url));
diff --git a/indra/llui/llurlaction.cpp b/indra/llui/llurlaction.cpp
index b6b450c2a1..fdae22cfa1 100644
--- a/indra/llui/llurlaction.cpp
+++ b/indra/llui/llurlaction.cpp
@@ -30,6 +30,7 @@
#include "llview.h"
#include "llwindow.h"
#include "llurlregistry.h"
+#include "v3dmath.h"
// global state for the callback functions
@@ -128,6 +129,23 @@ void LLUrlAction::showLocationOnMap(std::string url)
}
}
+void LLUrlAction::showParcelOnMap(std::string url)
+{
+ LLSD path_array = LLURI(url).pathArray();
+ auto path_parts = path_array.size();
+
+ if (path_parts < 3) // no parcel id
+ {
+ LL_WARNS() << "Global coordinates are missing in url: [" << url << "]" << LL_ENDL;
+ return;
+ }
+
+ LLVector3d parcel_pos = LLUrlEntryParcel::getParcelPos(LLUUID(LLURI::unescape(path_array[2])));
+ std::ostringstream pos;
+ pos << parcel_pos.mdV[VX] << '/' << parcel_pos.mdV[VY] << '/' << parcel_pos.mdV[VZ];
+ executeSLURL("secondlife:///app/worldmap_global/" + pos.str());
+}
+
void LLUrlAction::copyURLToClipboard(std::string url)
{
LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(url));
@@ -142,6 +160,16 @@ void LLUrlAction::copyLabelToClipboard(std::string url)
}
}
+std::string LLUrlAction::getURLLabel(std::string url)
+{
+ LLUrlMatch match;
+ if (LLUrlRegistry::instance().findUrl(url, match))
+ {
+ return match.getLabel();
+ }
+ return "";
+}
+
void LLUrlAction::showProfile(std::string url)
{
// Get id from 'secondlife:///app/{cmd}/{id}/{action}'
diff --git a/indra/llui/llurlaction.h b/indra/llui/llurlaction.h
index ac9741a7ad..8b7ab0e7c5 100644
--- a/indra/llui/llurlaction.h
+++ b/indra/llui/llurlaction.h
@@ -63,6 +63,8 @@ public:
/// if the Url specifies an SL location, show it on a map
static void showLocationOnMap(std::string url);
+ static void showParcelOnMap(std::string url);
+
/// perform the appropriate action for left-clicking on a Url
static void clickAction(std::string url, bool trusted_content);
@@ -72,6 +74,8 @@ public:
/// copy a Url to the clipboard
static void copyURLToClipboard(std::string url);
+ static std::string getURLLabel(std::string url);
+
/// if the Url specifies an SL command in the form like 'app/{cmd}/{id}/*', show its profile
static void showProfile(std::string url);
static std::string getUserID(std::string url);
diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp
index bcd13b7f0b..95603d7ed5 100644
--- a/indra/llui/llurlentry.cpp
+++ b/indra/llui/llurlentry.cpp
@@ -41,8 +41,7 @@
#include "lluicolortable.h"
#include "message.h"
#include "llexperiencecache.h"
-
-#define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))"
+#include "v3dmath.h"
// Utility functions
std::string localize_slapp_label(const std::string& url, const std::string& full_name);
@@ -1084,6 +1083,7 @@ LLUUID LLUrlEntryParcel::sSessionID(LLUUID::null);
LLHost LLUrlEntryParcel::sRegionHost;
bool LLUrlEntryParcel::sDisconnected(false);
std::set<LLUrlEntryParcel*> LLUrlEntryParcel::sParcelInfoObservers;
+std::map<LLUUID, LLVector3d> LLUrlEntryParcel::sParcelPos;
///
/// LLUrlEntryParcel Describes a Second Life parcel Url, e.g.,
@@ -1176,6 +1176,20 @@ void LLUrlEntryParcel::processParcelInfo(const LLParcelData& parcel_data)
url_entry->onParcelInfoReceived(parcel_data.parcel_id.asString(), label);
}
}
+ if (sParcelPos.find(parcel_data.parcel_id) == sParcelPos.end())
+ {
+ sParcelPos[parcel_data.parcel_id] = LLVector3d(parcel_data.global_x, parcel_data.global_y, parcel_data.global_z);
+ }
+}
+
+// static
+LLVector3d LLUrlEntryParcel::getParcelPos(const LLUUID& parcel_id)
+{
+ if (sParcelPos.find(parcel_id) != sParcelPos.end())
+ {
+ return sParcelPos[parcel_id];
+ }
+ return LLVector3d();
}
//
diff --git a/indra/llui/llurlentry.h b/indra/llui/llurlentry.h
index 6e7d2fc80f..efb5081103 100644
--- a/indra/llui/llurlentry.h
+++ b/indra/llui/llurlentry.h
@@ -41,6 +41,9 @@
#include <map>
class LLAvatarName;
+class LLVector3d;
+
+#define APP_HEADER_REGEX "((x-grid-location-info://[-\\w\\.]+/app)|(secondlife:///app))"
typedef boost::signals2::signal<void (const std::string& url,
const std::string& label,
@@ -434,6 +437,8 @@ public:
// Processes parcel label and triggers notifying observers.
static void processParcelInfo(const LLParcelData& parcel_data);
+ static LLVector3d getParcelPos(const LLUUID& parcel_id);
+
// Next setters are used to update agent and viewer connection information
// upon events like user login, viewer disconnect and user changing region host.
// These setters are made public to be accessible from newview and should not be
@@ -447,6 +452,7 @@ private:
static LLHost sRegionHost;
static bool sDisconnected;
static std::set<LLUrlEntryParcel*> sParcelInfoObservers;
+ static std::map<LLUUID, LLVector3d> sParcelPos;
};
///
diff --git a/indra/llwebrtc/llwebrtc.cpp b/indra/llwebrtc/llwebrtc.cpp
index 2ee6d912c1..b245774516 100644
--- a/indra/llwebrtc/llwebrtc.cpp
+++ b/indra/llwebrtc/llwebrtc.cpp
@@ -672,7 +672,10 @@ LLWebRTCPeerConnectionInterface *LLWebRTCImpl::newPeerConnection()
peerConnection->init(this);
mPeerConnections.emplace_back(peerConnection);
- peerConnection->enableSenderTracks(!mMute);
+ // Should it really start disabled?
+ // Seems like something doesn't get the memo and senders need to be reset later
+ // to remove the voice indicator from taskbar
+ peerConnection->enableSenderTracks(false);
if (mPeerConnections.empty())
{
setRecording(true);
@@ -706,7 +709,7 @@ void LLWebRTCImpl::freePeerConnection(LLWebRTCPeerConnectionInterface* peer_conn
LLWebRTCPeerConnectionImpl::LLWebRTCPeerConnectionImpl() :
mWebRTCImpl(nullptr),
mPeerConnection(nullptr),
- mMute(true),
+ mMute(MUTE_INITIAL),
mAnswerReceived(false)
{
}
@@ -741,6 +744,19 @@ void LLWebRTCPeerConnectionImpl::terminate()
}
}
+ // to remove 'Secondlife is recording' icon from taskbar
+ // if user was speaking
+ auto senders = mPeerConnection->GetSenders();
+ for (auto& sender : senders)
+ {
+ auto track = sender->track();
+ if (track)
+ {
+ track->set_enabled(false);
+ }
+ }
+ mPeerConnection->SetAudioRecording(false);
+
mPeerConnection->Close();
if (mLocalStream)
{
@@ -830,6 +846,7 @@ bool LLWebRTCPeerConnectionImpl::initializeConnection(const LLWebRTCPeerConnecti
audioOptions.auto_gain_control = true;
audioOptions.echo_cancellation = true;
audioOptions.noise_suppression = true;
+ audioOptions.init_recording_on_send = false;
mLocalStream = mPeerConnectionFactory->CreateLocalMediaStream("SLStream");
@@ -894,6 +911,7 @@ void LLWebRTCPeerConnectionImpl::enableSenderTracks(bool enable)
{
sender->track()->set_enabled(enable);
}
+ mPeerConnection->SetAudioRecording(enable);
}
}
@@ -934,9 +952,17 @@ void LLWebRTCPeerConnectionImpl::AnswerAvailable(const std::string &sdp)
void LLWebRTCPeerConnectionImpl::setMute(bool mute)
{
- mMute = mute;
+ EMicMuteState new_state = mute ? MUTE_MUTED : MUTE_UNMUTED;
+ if (new_state == mMute)
+ {
+ return; // no change
+ }
+ bool force_reset = mMute == MUTE_INITIAL && mute;
+ bool enable = !mute;
+ mMute = new_state;
+
mWebRTCImpl->PostSignalingTask(
- [this]()
+ [this, force_reset, enable]()
{
if (mPeerConnection)
{
@@ -948,16 +974,34 @@ void LLWebRTCPeerConnectionImpl::setMute(bool mute)
auto track = sender->track();
if (track)
{
- track->set_enabled(!mMute);
+ if (force_reset)
+ {
+ // Force notify observers
+ // Was it disabled too early?
+ // Without this microphone icon in Win's taskbar will stay
+ track->set_enabled(true);
+ }
+ track->set_enabled(enable);
}
}
+ mPeerConnection->SetAudioRecording(enable);
}
});
}
void LLWebRTCPeerConnectionImpl::resetMute()
{
- setMute(mMute);
+ switch(mMute)
+ {
+ case MUTE_MUTED:
+ setMute(true);
+ break;
+ case MUTE_UNMUTED:
+ setMute(false);
+ break;
+ default:
+ break;
+ }
}
void LLWebRTCPeerConnectionImpl::setReceiveVolume(float volume)
diff --git a/indra/llwebrtc/llwebrtc_impl.h b/indra/llwebrtc/llwebrtc_impl.h
index 99accb2c20..dfdb19e9be 100644
--- a/indra/llwebrtc/llwebrtc_impl.h
+++ b/indra/llwebrtc/llwebrtc_impl.h
@@ -425,7 +425,12 @@ class LLWebRTCPeerConnectionImpl : public LLWebRTCPeerConnectionInterface,
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> mPeerConnectionFactory;
- bool mMute;
+ typedef enum {
+ MUTE_INITIAL,
+ MUTE_MUTED,
+ MUTE_UNMUTED,
+ } EMicMuteState;
+ EMicMuteState mMute;
// signaling
std::vector<LLWebRTCSignalingObserver *> mSignalingObserverList;
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 8960519bc2..2656f21def 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -76,6 +76,11 @@
#pragma comment(lib, "dxguid.lib") // needed for llurlentry test to build on some systems
#pragma comment(lib, "dinput8")
+#pragma comment(lib, "UxTheme.lib")
+#pragma comment(lib, "Dwmapi.lib")
+#include <Uxtheme.h>
+#include <dwmapi.h> // needed for DwmSetWindowAttribute to set window theme
+
const S32 MAX_MESSAGE_PER_UPDATE = 20;
const S32 BITS_PER_PIXEL = 32;
const S32 MAX_NUM_RESOLUTIONS = 32;
@@ -85,6 +90,10 @@ const F32 ICON_FLASH_TIME = 0.5f;
#define USER_DEFAULT_SCREEN_DPI 96 // Win7
#endif
+#ifndef WM_DWMCOLORIZATIONCOLORCHANGED
+#define WM_DWMCOLORIZATIONCOLORCHANGED 0x0320
+#endif
+
// Claim a couple unused GetMessage() message IDs
const UINT WM_DUMMY_(WM_USER + 0x0017);
const UINT WM_POST_FUNCTION_(WM_USER + 0x0018);
@@ -104,6 +113,7 @@ static std::thread::id sMainThreadId;
LPWSTR gIconResource = IDI_APPLICATION;
+LPWSTR gIconSmallResource = IDI_APPLICATION;
LPDIRECTINPUT8 gDirectInput8;
LLW32MsgCallback gAsyncMsgCallback = NULL;
@@ -137,6 +147,17 @@ typedef HRESULT(STDAPICALLTYPE *GetDpiForMonitorType)(
_Out_ UINT *dpiX,
_Out_ UINT *dpiY);
+typedef enum PREFERRED_APP_MODE
+{
+ DEFAULT,
+ ALLOW_DARK,
+ FORCE_DARK,
+ FORCE_LIGHT,
+ MAX
+} PREFERRED_APP_MODE;
+
+typedef PREFERRED_APP_MODE(WINAPI* fnSetPreferredAppMode)(PREFERRED_APP_MODE mode);
+
//
// LLWindowWin32
//
@@ -512,6 +533,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
mFSAASamples = fsaa_samples;
mIconResource = gIconResource;
+ mIconSmallResource = gIconSmallResource;
mOverrideAspectRatio = 0.f;
mNativeAspectRatio = 0.f;
mInputProcessingPaused = false;
@@ -846,6 +868,8 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
// Initialize (boot strap) the Language text input management,
// based on the system's (or user's) default settings.
allowLanguageTextInput(NULL, false);
+ updateWindowTheme();
+ setCustomIcon();
}
@@ -3020,6 +3044,17 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
WINDOW_IMP_POST(window_imp->mMouseVanish = true);
}
}
+ // Check if theme-related settings changed
+ else if (l_param && (wcscmp((LPCWSTR)l_param, L"ImmersiveColorSet") == 0))
+ {
+ WINDOW_IMP_POST(window_imp->updateWindowTheme());
+ }
+ }
+ break;
+
+ case WM_DWMCOLORIZATIONCOLORCHANGED:
+ {
+ WINDOW_IMP_POST(window_imp->updateWindowTheme());
}
break;
@@ -4962,3 +4997,69 @@ void LLWindowWin32::updateWindowRect()
});
}
}
+
+bool LLWindowWin32::isSystemAppDarkMode()
+{
+ HKEY hKey;
+ DWORD dwValue = 1; // Default to light theme
+ DWORD dwSize = sizeof(DWORD);
+
+ // Check registry for system theme preference
+ LSTATUS ret_code =
+ RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", 0, KEY_READ, &hKey);
+ if (ERROR_SUCCESS == ret_code)
+ {
+ if (RegQueryValueExW(hKey, L"AppsUseLightTheme", NULL, NULL, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS)
+ {
+ // If AppsUseLightTheme is not found, check SystemUsesLightTheme
+ dwSize = sizeof(DWORD);
+ RegQueryValueExW(hKey, L"SystemUsesLightTheme", NULL, NULL, (LPBYTE)&dwValue, &dwSize);
+ }
+ RegCloseKey(hKey);
+ }
+
+ // Return true if dark mode
+ return dwValue == 0;
+}
+
+void LLWindowWin32::updateWindowTheme()
+{
+ bool use_dark_mode = isSystemAppDarkMode();
+ if (use_dark_mode == mCurrentDarkMode)
+ {
+ return;
+ }
+ mCurrentDarkMode = use_dark_mode;
+
+ HMODULE hUxTheme = LoadLibraryExW(L"uxtheme.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
+ if (hUxTheme)
+ {
+ auto SetPreferredAppMode = (fnSetPreferredAppMode)GetProcAddress(hUxTheme, "SetPreferredAppMode");
+ if (SetPreferredAppMode)
+ {
+ SetPreferredAppMode(use_dark_mode ? ALLOW_DARK : FORCE_LIGHT);
+ }
+ FreeLibrary(hUxTheme);
+ }
+ BOOL dark_mode(use_dark_mode);
+ DwmSetWindowAttribute(mWindowHandle, DWMWA_USE_IMMERSIVE_DARK_MODE, &dark_mode, sizeof(dark_mode));
+
+ LL_INFOS("Window") << "Viewer window theme is set to " << (use_dark_mode ? "dark" : "light") << " mode" << LL_ENDL;
+}
+
+void LLWindowWin32::setCustomIcon()
+{
+ if (mWindowHandle)
+ {
+ HICON hDefaultIcon = LoadIcon(mhInstance, mIconResource);
+ HICON hSmallIcon = LoadIcon(mhInstance, mIconSmallResource);
+ mWindowThread->post([=]()
+ {
+ SendMessage(mWindowHandle, WM_SETICON, ICON_BIG, (LPARAM)hDefaultIcon);
+ SendMessage(mWindowHandle, WM_SETICON, ICON_SMALL, (LPARAM)hSmallIcon);
+
+ SetClassLongPtr(mWindowHandle, GCLP_HICON, (LONG_PTR)hDefaultIcon);
+ SetClassLongPtr(mWindowHandle, GCLP_HICONSM, (LONG_PTR)hSmallIcon);
+ });
+ }
+}
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index 561f07d388..7196706f87 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -214,6 +214,7 @@ protected:
bool mCustomGammaSet;
LPWSTR mIconResource;
+ LPWSTR mIconSmallResource;
bool mInputProcessingPaused;
// The following variables are for Language Text Input control.
@@ -246,6 +247,11 @@ protected:
RECT mRect;
RECT mClientRect;
+ void updateWindowTheme();
+ bool isSystemAppDarkMode();
+ void setCustomIcon();
+ bool mCurrentDarkMode { false };
+
struct LLWindowWin32Thread;
LLWindowWin32Thread* mWindowThread = nullptr;
LLThreadSafeQueue<std::function<void()>> mFunctionQueue;
@@ -281,6 +287,7 @@ private:
extern LLW32MsgCallback gAsyncMsgCallback;
extern LPWSTR gIconResource;
+extern LPWSTR gIconSmallResource;
S32 OSMessageBoxWin32(const std::string& text, const std::string& caption, U32 type);
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 019d656471..9b30902de9 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1605,6 +1605,7 @@ if (WINDOWS)
res-sdl/ll_icon.BMP
res/ll_icon.BMP
res/ll_icon.ico
+ res/ll_icon_small.ico
res/resource.h
res/toolpickobject.cur
res/toolpickobject2.cur
@@ -1913,6 +1914,12 @@ if (WINDOWS)
)
endif (ADDRESS_SIZE EQUAL 64)
+ if (TARGET ll::discord_sdk)
+ list(APPEND COPY_INPUT_DEPENDENCIES
+ ${SHARED_LIB_STAGING_DIR}/discord_partner_sdk.dll
+ )
+ endif ()
+
if (TARGET ll::openal)
list(APPEND COPY_INPUT_DEPENDENCIES
${SHARED_LIB_STAGING_DIR}/OpenAL32.dll
@@ -1929,6 +1936,7 @@ if (WINDOWS)
--arch=${ARCH}
--artwork=${ARTWORK_DIR}
"--bugsplat=${BUGSPLAT_DB}"
+ "--discord=${USE_DISCORD}"
"--openal=${USE_OPENAL}"
"--tracy=${USE_TRACY}"
--build=${CMAKE_CURRENT_BINARY_DIR}
@@ -1967,6 +1975,7 @@ if (WINDOWS)
--arch=${ARCH}
--artwork=${ARTWORK_DIR}
"--bugsplat=${BUGSPLAT_DB}"
+ "--discord=${USE_DISCORD}"
"--openal=${USE_OPENAL}"
"--tracy=${USE_TRACY}"
--build=${CMAKE_CURRENT_BINARY_DIR}
@@ -2044,6 +2053,7 @@ if (WINDOWS)
--arch=${ARCH}
--artwork=${ARTWORK_DIR}
"--bugsplat=${BUGSPLAT_DB}"
+ "--discord=${USE_DISCORD}"
"--openal=${USE_OPENAL}"
"--tracy=${USE_TRACY}"
--build=${CMAKE_CURRENT_BINARY_DIR}
@@ -2151,7 +2161,7 @@ if (ENABLE_MEDIA_PLUGINS)
endif ()
if (USE_DISCORD)
- target_link_libraries(${VIEWER_BINARY_NAME} ll::discord )
+ target_link_libraries(${VIEWER_BINARY_NAME} ll::discord_sdk )
endif ()
if( TARGET ll::intel_memops )
@@ -2269,6 +2279,7 @@ if (LINUX)
--arch=${ARCH}
--artwork=${ARTWORK_DIR}
"--bugsplat=${BUGSPLAT_DB}"
+ "--discord=${USE_DISCORD}"
"--openal=${USE_OPENAL}"
"--tracy=${USE_TRACY}"
--build=${CMAKE_CURRENT_BINARY_DIR}
@@ -2351,6 +2362,7 @@ if (LINUX)
--arch=${ARCH}
--artwork=${ARTWORK_DIR}
"--bugsplat=${BUGSPLAT_DB}"
+ "--discord=${USE_DISCORD}"
"--openal=${USE_OPENAL}"
"--tracy=${USE_TRACY}"
--build=${CMAKE_CURRENT_BINARY_DIR}
@@ -2453,6 +2465,7 @@ if (DARWIN)
--arch=${ARCH}
--artwork=${ARTWORK_DIR}
"--bugsplat=${BUGSPLAT_DB}"
+ "--discord=${USE_DISCORD}"
"--openal=${USE_OPENAL}"
"--tracy=${USE_TRACY}"
--build=${CMAKE_CURRENT_BINARY_DIR}
@@ -2507,6 +2520,7 @@ if (DARWIN)
--arch=${ARCH}
--artwork=${ARTWORK_DIR}
"--bugsplat=${BUGSPLAT_DB}"
+ "--discord=${USE_DISCORD}"
"--openal=${USE_OPENAL}"
"--tracy=${USE_TRACY}"
--build=${CMAKE_CURRENT_BINARY_DIR}
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index ff9f2b96a7..2b26eb105e 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1219,13 +1219,13 @@
<key>DiskCachePercentOfTotal</key>
<map>
<key>Comment</key>
- <string>The percent of total cache size (defined by CacheSize) to use for the disk cache</string>
+ <string>The percent of total cache size (defined by CacheSize) to use for the disk cache (ex: asset storage, excludes textures)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
- <real>40.0</real>
+ <real>35.0</real>
</map>
<key>DiskCacheDirName</key>
<map>
@@ -1269,7 +1269,7 @@
<key>Type</key>
<string>U32</string>
<key>Value</key>
- <integer>4096</integer>
+ <integer>6144</integer>
</map>
<key>CacheValidateCounter</key>
<map>
@@ -9716,6 +9716,17 @@
<key>Value</key>
<integer>1</integer>
</map>
+ <key>ObscureBalanceInStatusBar</key>
+ <map>
+ <key>Comment</key>
+ <string>If true, balance will be shows as '*'</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>RenderUIBuffer</key>
<map>
<key>Comment</key>
@@ -13940,7 +13951,7 @@
<key>FullScreen</key>
<map>
<key>Comment</key>
- <string>run a fullscreen session</string>
+ <string>Run a fullscreen session. MacOS not supported</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@@ -16837,5 +16848,49 @@
<key>Value</key>
<integer>31</integer>
</map>
+ <key>EnableSelectionHints</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether or not to send editing hints to animate the arm when editing an object.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnableLookAtTarget</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether or not to animate the avatar head and send look at targets when moving the cursor or focusing on objects</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>LimitLookAtTarget</key>
+ <map>
+ <key>Comment</key>
+ <string>Whether or not to clamp the look at targets around the avatar head before sending</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>LimitLookAtTargetDistance</key>
+ <map>
+ <key>Comment</key>
+ <string>Distance to limit look at target to</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <integer>2</integer>
+ </map>
</map>
</llsd>
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index 5211884bc2..93cc4941f1 100644
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -1094,12 +1094,12 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it
{
gAgentAvatarp->setCompositeUpdatesEnabled(true);
- // If we have not yet declouded, we may want to use
+ // If we have not yet loaded core parts, we may want to use
// baked texture UUIDs sent from the first objectUpdate message
- // don't overwrite these. If we have already declouded, we've saved
- // these ids as the last known good textures and can invalidate without
- // re-clouding.
- if (!gAgentAvatarp->getIsCloud())
+ // don't overwrite these. If we have parts already, we've saved
+ // these texture ids as the last known good textures and can
+ // invalidate without having to recloud avatar.
+ if (!gAgentAvatarp->getHasMissingParts())
{
gAgentAvatarp->invalidateAll();
}
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 4050bda024..71dec10e01 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -856,7 +856,7 @@ void LLWearableHoldingPattern::checkMissingWearables()
// was requested but none was found, create a default asset as a replacement.
// In all other cases, don't do anything.
// For critical types (shape/hair/skin/eyes), this will keep the avatar as a cloud
- // due to logic in LLVOAvatarSelf::getIsCloud().
+ // due to logic in LLVOAvatarSelf::getHasMissingParts().
// For non-critical types (tatoo, socks, etc.) the wearable will just be missing.
(requested_by_type[type] > 0) &&
((type == LLWearableType::WT_PANTS) || (type == LLWearableType::WT_SHIRT) || (type == LLWearableType::WT_SKIRT)))
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 53a3978086..32f4421ce2 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -3178,7 +3178,15 @@ bool LLAppViewer::initWindow()
.height(gSavedSettings.getU32("WindowHeight"))
.min_width(gSavedSettings.getU32("MinWindowWidth"))
.min_height(gSavedSettings.getU32("MinWindowHeight"))
+#ifdef LL_DARWIN
+ // Setting it to true causes black screen with no UI displayed.
+ // Given that it's a DEBUG settings and application goes fullscreen
+ // on mac simply by expanding it, it was decided to not support/use
+ // this setting on mac.
+ .fullscreen(false)
+#else // LL_DARWIN
.fullscreen(gSavedSettings.getBOOL("FullScreen"))
+#endif
.ignore_pixel_depth(ignorePixelDepth)
.first_run(mIsFirstRun);
@@ -4365,8 +4373,8 @@ bool LLAppViewer::initCache()
const std::string cache_dir_name = gSavedSettings.getString("DiskCacheDirName");
const U32 MB = 1024 * 1024;
- const uintmax_t MIN_CACHE_SIZE = 256 * MB;
- const uintmax_t MAX_CACHE_SIZE = 9984ll * MB;
+ const uintmax_t MIN_CACHE_SIZE = 896 * MB;
+ const uintmax_t MAX_CACHE_SIZE = 32768ll * MB;
const uintmax_t setting_cache_total_size = uintmax_t(gSavedSettings.getU32("CacheSize")) * MB;
const uintmax_t cache_total_size = llclamp(setting_cache_total_size, MIN_CACHE_SIZE, MAX_CACHE_SIZE);
const F64 disk_cache_percent = gSavedSettings.getF32("DiskCachePercentOfTotal");
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index f3214e2a20..d5cce28a3d 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -460,6 +460,7 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,
// *FIX: global
gIconResource = MAKEINTRESOURCE(IDI_LL_ICON);
#endif
+ gIconSmallResource = MAKEINTRESOURCE(IDI_LL_ICON_SMALL);
LLAppViewerWin32* viewer_app_ptr = new LLAppViewerWin32(ll_convert_wide_to_string(pCmdLine).c_str());
diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp
index af5a46742c..774e8fd4c5 100644
--- a/indra/newview/llconversationmodel.cpp
+++ b/indra/newview/llconversationmodel.cpp
@@ -300,7 +300,7 @@ void LLConversationItemSession::updateName(LLConversationItemParticipant* partic
for (auto itemp : mChildren)
{
- LLConversationItem* current_participant = dynamic_cast<LLConversationItem*>(itemp);
+ LLConversationItem* current_participant = dynamic_cast<LLConversationItem*>(itemp.get());
// Add the avatar uuid to the list (except if it's the own agent uuid)
if (current_participant->getUUID() != gAgentID)
{
@@ -329,6 +329,7 @@ void LLConversationItemSession::updateName(LLConversationItemParticipant* partic
void LLConversationItemSession::removeParticipant(LLConversationItemParticipant* participant)
{
+ LLPointer<LLFolderViewModelItem> holder(participant);
removeChild(participant);
mNeedsRefresh = true;
updateName(participant);
@@ -360,15 +361,10 @@ void LLConversationItemSession::clearAndDeparentModels()
for (child_list_t::iterator it = mChildren.begin(); it != mChildren.end();)
{
LLFolderViewModelItem* child = *it;
- if (child->getNumRefs() == 0)
+ // Note that model might still be assigned to some view/widget
+ // and have a different parent
+ if (child->getParent() == this)
{
- // LLConversationItemParticipant can be created but not assigned to any view,
- // it was waiting for an "add_participant" event to be processed
- delete child;
- }
- else
- {
- // Model is still assigned to some view/widget
child->setParent(NULL);
}
it = mChildren.erase(it);
@@ -383,7 +379,7 @@ LLConversationItemParticipant* LLConversationItemSession::findParticipant(const
child_list_t::iterator iter;
for (iter = mChildren.begin(); iter != mChildren.end(); iter++)
{
- participant = dynamic_cast<LLConversationItemParticipant*>(*iter);
+ participant = dynamic_cast<LLConversationItemParticipant*>((*iter).get());
if (participant && participant->hasSameValue(participant_id))
{
break;
@@ -493,7 +489,7 @@ const bool LLConversationItemSession::getTime(F64& time) const
child_list_t::const_iterator iter;
for (iter = mChildren.begin(); iter != mChildren.end(); iter++)
{
- participant = dynamic_cast<LLConversationItemParticipant*>(*iter);
+ participant = dynamic_cast<LLConversationItemParticipant*>((*iter).get());
F64 participant_time;
if (participant && participant->getTime(participant_time))
{
@@ -517,7 +513,7 @@ void LLConversationItemSession::dumpDebugData(bool dump_children)
{
for (child_list_t::iterator iter = mChildren.begin(); iter != mChildren.end(); iter++)
{
- LLConversationItemParticipant* participant = dynamic_cast<LLConversationItemParticipant*>(*iter);
+ LLConversationItemParticipant* participant = dynamic_cast<LLConversationItemParticipant*>((*iter).get());
if (participant)
{
participant->dumpDebugData();
diff --git a/indra/newview/llfloaterchatmentionpicker.cpp b/indra/newview/llfloaterchatmentionpicker.cpp
index 1cfed122a9..a3eb286375 100644
--- a/indra/newview/llfloaterchatmentionpicker.cpp
+++ b/indra/newview/llfloaterchatmentionpicker.cpp
@@ -88,7 +88,7 @@ uuid_vec_t LLFloaterChatMentionPicker::getParticipantIds()
LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = item->getChildrenEnd();
while (current_participant_model != end_participant_model)
{
- LLConversationItem* participant_model = dynamic_cast<LLConversationItem*>(*current_participant_model);
+ LLConversationItem* participant_model = dynamic_cast<LLConversationItem*>((*current_participant_model).get());
if (participant_model)
{
avatar_ids.push_back(participant_model->getUUID());
diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp
index f254fdafaf..42a5df5d17 100644
--- a/indra/newview/llfloaterimagepreview.cpp
+++ b/indra/newview/llfloaterimagepreview.cpp
@@ -32,6 +32,7 @@
#include "llimagetga.h"
#include "llimagejpeg.h"
#include "llimagepng.h"
+#include "llimagej2c.h"
#include "llagent.h"
#include "llagentbenefits.h"
@@ -43,6 +44,10 @@
#include "llrender.h"
#include "llface.h"
#include "llfocusmgr.h"
+#include "llfilesystem.h"
+#include "llfloaterperms.h"
+#include "llnotificationsutil.h"
+#include "llstatusbar.h" // can_afford_transaction()
#include "lltextbox.h"
#include "lltoolmgr.h"
#include "llui.h"
@@ -52,6 +57,7 @@
#include "llvoavatar.h"
#include "pipeline.h"
#include "lluictrlfactory.h"
+#include "llviewermenufile.h" // upload_new_resource()
#include "llviewershadermgr.h"
#include "llviewertexturelist.h"
#include "llstring.h"
@@ -140,7 +146,7 @@ bool LLFloaterImagePreview::postBuild()
}
}
- getChild<LLUICtrl>("ok_btn")->setCommitCallback(boost::bind(&LLFloaterNameDesc::onBtnOK, this));
+ getChild<LLUICtrl>("ok_btn")->setCommitCallback(boost::bind(&LLFloaterImagePreview::onBtnOK, this));
return true;
}
@@ -244,6 +250,59 @@ void LLFloaterImagePreview::clearAllPreviewTextures()
}
//-----------------------------------------------------------------------------
+// onBtnOK()
+//-----------------------------------------------------------------------------
+void LLFloaterImagePreview::onBtnOK()
+{
+ getChildView("ok_btn")->setEnabled(false); // don't allow inadvertent extra uploads
+
+ S32 expected_upload_cost = getExpectedUploadCost();
+ if (can_afford_transaction(expected_upload_cost))
+ {
+ LL_INFOS() << "saving texture: " << mRawImagep->getWidth() << "x" << mRawImagep->getHeight() << LL_ENDL;
+ // gen a new uuid for this asset
+ LLTransactionID tid;
+ tid.generate();
+ LLAssetID new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
+
+ LLPointer<LLImageJ2C> formatted = new LLImageJ2C;
+
+ if (formatted->encode(mRawImagep, 0.0f))
+ {
+ LLFileSystem fmt_file(new_asset_id, LLAssetType::AT_TEXTURE, LLFileSystem::WRITE);
+ fmt_file.write(formatted->getData(), formatted->getDataSize());
+
+ LLResourceUploadInfo::ptr_t assetUploadInfo(new LLResourceUploadInfo(
+ tid, LLAssetType::AT_TEXTURE,
+ getChild<LLUICtrl>("name_form")->getValue().asString(),
+ getChild<LLUICtrl>("description_form")->getValue().asString(),
+ 0,
+ LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
+ LLFloaterPerms::getNextOwnerPerms("Uploads"),
+ LLFloaterPerms::getGroupPerms("Uploads"),
+ LLFloaterPerms::getEveryonePerms("Uploads"),
+ expected_upload_cost
+ ));
+
+ upload_new_resource(assetUploadInfo);
+ }
+ else
+ {
+ LLNotificationsUtil::add("ErrorEncodingImage");
+ LL_WARNS() << "Error encoding image" << LL_ENDL;
+ }
+ }
+ else
+ {
+ LLSD args;
+ args["COST"] = llformat("%d", expected_upload_cost);
+ LLNotificationsUtil::add("ErrorCannotAffordUpload", args);
+ }
+
+ closeFloater(false);
+}
+
+//-----------------------------------------------------------------------------
// draw()
//-----------------------------------------------------------------------------
void LLFloaterImagePreview::draw()
@@ -364,19 +423,6 @@ bool LLFloaterImagePreview::loadImage(const std::string& src_filename)
return false;
}
- S32 max_width = gSavedSettings.getS32("max_texture_dimension_X");
- S32 max_height = gSavedSettings.getS32("max_texture_dimension_Y");
-
- if ((image_info.getWidth() > max_width) || (image_info.getHeight() > max_height))
- {
- LLStringUtil::format_map_t args;
- args["WIDTH"] = llformat("%d", max_width);
- args["HEIGHT"] = llformat("%d", max_height);
-
- mImageLoadError = LLTrans::getString("texture_load_dimensions_error", args);
- return false;
- }
-
// Load the image
LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
if (image.isNull())
@@ -399,6 +445,46 @@ bool LLFloaterImagePreview::loadImage(const std::string& src_filename)
image->setLastError("Image files with less than 3 or more than 4 components are not supported.");
return false;
}
+ // Downscale images to fit the max_texture_dimensions_*
+ S32 max_width = gSavedSettings.getS32("max_texture_dimension_X");
+ S32 max_height = gSavedSettings.getS32("max_texture_dimension_Y");
+
+ S32 orig_width = raw_image->getWidth();
+ S32 orig_height = raw_image->getHeight();
+
+ if (orig_width > max_width || orig_height > max_height)
+ {
+ // Calculate scale factors
+ F32 width_scale = (F32)max_width / (F32)orig_width;
+ F32 height_scale = (F32)max_height / (F32)orig_height;
+ F32 scale = llmin(width_scale, height_scale);
+
+ // Calculate new dimensions, preserving aspect ratio
+ S32 new_width = LLImageRaw::contractDimToPowerOfTwo(
+ llclamp((S32)llroundf(orig_width * scale), 4, max_width)
+ );
+ S32 new_height = LLImageRaw::contractDimToPowerOfTwo(
+ llclamp((S32)llroundf(orig_height * scale), 4, max_height)
+ );
+
+ if (!raw_image->scale(new_width, new_height))
+ {
+ LL_WARNS() << "Failed to scale image from "
+ << orig_width << "x" << orig_height
+ << " to " << new_width << "x" << new_height << LL_ENDL;
+ return false;
+ }
+
+ // Inform the resident about the resized image
+ LLSD subs;
+ subs["[ORIGINAL_WIDTH]"] = orig_width;
+ subs["[ORIGINAL_HEIGHT]"] = orig_height;
+ subs["[NEW_WIDTH]"] = new_width;
+ subs["[NEW_HEIGHT]"] = new_height;
+ subs["[MAX_WIDTH]"] = max_width;
+ subs["[MAX_HEIGHT]"] = max_height;
+ LLNotificationsUtil::add("ImageUploadResized", subs);
+ }
raw_image->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
mRawImagep = raw_image;
diff --git a/indra/newview/llfloaterimagepreview.h b/indra/newview/llfloaterimagepreview.h
index 9bc57246cf..5e5f4932c2 100644
--- a/indra/newview/llfloaterimagepreview.h
+++ b/indra/newview/llfloaterimagepreview.h
@@ -126,6 +126,8 @@ public:
void clearAllPreviewTextures();
+ void onBtnOK();
+
protected:
static void onPreviewTypeCommit(LLUICtrl*,void*);
void draw() override;
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index 59ae8a9a81..bff0457a7d 100644
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -460,7 +460,7 @@ void LLFloaterIMContainer::processParticipantsStyleUpdate()
LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = session_model->getChildrenEnd();
while (current_participant_model != end_participant_model)
{
- LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(*current_participant_model);
+ LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>((*current_participant_model).get());
if (participant_model)
{
// Get the avatar name for this participant id from the cache and update the model
@@ -511,7 +511,7 @@ void LLFloaterIMContainer::idleUpdate()
bool can_ban = haveAbilityToBan();
while (current_participant_model != end_participant_model)
{
- LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(*current_participant_model);
+ LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>((*current_participant_model).get());
if (participant_model)
{
participant_model->setModeratorOptionsVisible(is_moderator);
@@ -1882,7 +1882,7 @@ LLConversationItem* LLFloaterIMContainer::addConversationListItem(const LLUUID&
LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = item->getChildrenEnd();
while (current_participant_model != end_participant_model)
{
- LLConversationItem* participant_model = dynamic_cast<LLConversationItem*>(*current_participant_model);
+ LLConversationItem* participant_model = dynamic_cast<LLConversationItem*>((*current_participant_model).get());
LLConversationViewParticipant* participant_view = createConversationViewParticipant(participant_model);
participant_view->addToFolder(widget);
current_participant_model++;
diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp
index 733e178de3..5160ac4d34 100644
--- a/indra/newview/llfloaterimsessiontab.cpp
+++ b/indra/newview/llfloaterimsessiontab.cpp
@@ -107,26 +107,6 @@ LLFloaterIMSessionTab::~LLFloaterIMSessionTab()
delete mRefreshTimer;
LLIMMgr::instance().removeSessionObserver(this);
mEmojiCloseConn.disconnect();
-
- LLFloaterIMContainer* im_container = LLFloaterIMContainer::findInstance();
- if (im_container)
- {
- LLParticipantList* session = dynamic_cast<LLParticipantList*>(im_container->getSessionModel(mSessionID));
- if (session)
- {
- for (const conversations_widgets_map::value_type& widget_pair : mConversationsWidgets)
- {
- LLFolderViewItem* widget = widget_pair.second;
- LLFolderViewModelItem* item_vmi = widget->getViewModelItem();
- if (item_vmi && item_vmi->getNumRefs() == 1)
- {
- // This is the last pointer, remove participant from session
- // before participant gets deleted on destroyView.
- session->removeChild(item_vmi);
- }
- }
- }
- }
}
// static
@@ -731,7 +711,7 @@ void LLFloaterIMSessionTab::buildConversationViewParticipant()
LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = item->getChildrenEnd();
while (current_participant_model != end_participant_model)
{
- LLConversationItem* participant_model = dynamic_cast<LLConversationItem*>(*current_participant_model);
+ LLConversationItem* participant_model = dynamic_cast<LLConversationItem*>((*current_participant_model).get());
if (participant_model)
{
addConversationViewParticipant(participant_model);
@@ -775,27 +755,6 @@ void LLFloaterIMSessionTab::removeConversationViewParticipant(const LLUUID& part
LLFolderViewItem* widget = get_ptr_in_map(mConversationsWidgets,participant_id);
if (widget)
{
- LLFolderViewModelItem* item_vmi = widget->getViewModelItem();
- if (item_vmi && item_vmi->getNumRefs() == 1)
- {
- // This is the last pointer, remove participant from session
- // before participant gets deleted on destroyView.
- //
- // Floater (widget) and participant's view can simultaneously
- // co-own the model, in which case view is responsible for
- // the deletion and floater is free to clear and recreate
- // the list, yet there are cases where only widget owns
- // the pointer so it should do the cleanup.
- // See "add_participant".
- //
- // Todo: If it keeps causing issues turn participants
- // into LLPointers in the session
- LLParticipantList* session = getParticipantList();
- if (session)
- {
- session->removeChild(item_vmi);
- }
- }
widget->destroyView();
}
mConversationsWidgets.erase(participant_id);
@@ -861,7 +820,7 @@ void LLFloaterIMSessionTab::refreshConversation()
LLIMSpeakerMgr *speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
while (current_participant_model != end_participant_model)
{
- LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>(*current_participant_model);
+ LLConversationItemParticipant* participant_model = dynamic_cast<LLConversationItemParticipant*>((*current_participant_model).get());
if (speaker_mgr && participant_model)
{
LLSpeaker *participant_speaker = speaker_mgr->findSpeaker(participant_model->getUUID());
diff --git a/indra/newview/llfloatermediasettings.cpp b/indra/newview/llfloatermediasettings.cpp
index 2496887c9d..81eab52e6c 100644
--- a/indra/newview/llfloatermediasettings.cpp
+++ b/indra/newview/llfloatermediasettings.cpp
@@ -180,8 +180,15 @@ void LLFloaterMediaSettings::onClose(bool app_quitting)
////////////////////////////////////////////////////////////////////////////////
//static
-void LLFloaterMediaSettings::initValues( const LLSD& media_settings, bool editable )
+void LLFloaterMediaSettings::initValues( const LLSD& media_settings, bool editable, bool has_media_info, bool multiple_media, bool multiple_valid_media)
{
+ if (!sInstance)
+ {
+ return;
+ }
+ sInstance->mIdenticalHasMediaInfo = has_media_info;
+ sInstance->mMultipleMedia = multiple_media;
+ sInstance->mMultipleValidMedia = multiple_valid_media;
if (sInstance->hasFocus()) return;
// Clear values
diff --git a/indra/newview/llfloatermediasettings.h b/indra/newview/llfloatermediasettings.h
index 38730ddc98..7ed7ab246f 100644
--- a/indra/newview/llfloatermediasettings.h
+++ b/indra/newview/llfloatermediasettings.h
@@ -48,7 +48,7 @@ public:
static LLFloaterMediaSettings* getInstance();
static bool instanceExists();
static void apply();
- static void initValues( const LLSD& media_settings , bool editable);
+ static void initValues( const LLSD& media_settings , bool editable, bool has_media_info, bool multiple_media, bool multiple_valid_media);
static void clearValues( bool editable);
LLPanelMediaSettingsSecurity* getPanelSecurity(){return mPanelMediaSettingsSecurity;};
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 234885eba7..6a6766fb3f 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -165,7 +165,7 @@ bool LLFloaterModelPreview::postBuild()
for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod)
{
LLComboBox* lod_source_combo = getChild<LLComboBox>("lod_source_" + lod_name[lod]);
- lod_source_combo->setCommitCallback(boost::bind(&LLFloaterModelPreview::onLoDSourceCommit, this, lod, true));
+ lod_source_combo->setCommitCallback(boost::bind(&LLFloaterModelPreview::onLoDSourceCommit, this, lod));
lod_source_combo->setCurrentByIndex(mLODMode[lod]);
getChild<LLButton>("lod_browse_" + lod_name[lod])->setCommitCallback(boost::bind(&LLFloaterModelPreview::onBrowseLOD, this, lod));
@@ -766,7 +766,7 @@ void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit)
LLComboBox* lod_source_combo = getChild<LLComboBox>("lod_source_" + lod_name[i]);
if (lod_source_combo->getCurrentIndex() == LLModelPreview::USE_LOD_ABOVE)
{
- onLoDSourceCommit(i, false);
+ onLoDSourceCommit(i);
}
else
{
@@ -1760,7 +1760,7 @@ void LLFloaterModelPreview::toggleCalculateButton(bool visible)
}
}
-void LLFloaterModelPreview::onLoDSourceCommit(S32 lod, bool refresh_ui)
+void LLFloaterModelPreview::onLoDSourceCommit(S32 lod)
{
mModelPreview->updateLodControls(lod);
diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h
index f8f2cd7812..7b652a3613 100644
--- a/indra/newview/llfloatermodelpreview.h
+++ b/indra/newview/llfloatermodelpreview.h
@@ -206,7 +206,7 @@ private:
void onClickCalculateBtn();
void onJointListSelection();
- void onLoDSourceCommit(S32 lod, bool refresh_ui);
+ void onLoDSourceCommit(S32 lod);
void modelUpdated(bool calculate_visible);
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 36a68a7017..dc5346634e 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -528,6 +528,10 @@ bool LLFloaterPreference::postBuild()
getChild<LLComboBox>("language_combobox")->add("System default", LLSD("default"), ADD_TOP, true);
}
+#ifndef LL_DISCORD
+ getChild<LLTabContainer>("privacy_tab_container")->childDisable("privacy_preferences_discord");
+#endif
+
return true;
}
diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp
index 8cc01f6dc6..01108b5cfa 100644
--- a/indra/newview/llfloatersettingsdebug.cpp
+++ b/indra/newview/llfloatersettingsdebug.cpp
@@ -207,14 +207,14 @@ void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp)
mSettingNameText->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)
+ if (mOldText != new_text)
{
mComment->setText(controlp->getComment());
+ mOldText = new_text;
}
mValSpinner1->setMaxValue(F32_MAX);
@@ -467,6 +467,7 @@ void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp)
}
default:
mComment->setText(std::string("unknown"));
+ mOldText = "unknown";
break;
}
}
diff --git a/indra/newview/llfloatersettingsdebug.h b/indra/newview/llfloatersettingsdebug.h
index b813cf4a74..8781cd3b67 100644
--- a/indra/newview/llfloatersettingsdebug.h
+++ b/indra/newview/llfloatersettingsdebug.h
@@ -82,6 +82,7 @@ protected:
LLColorSwatchCtrl* mColorSwatch = nullptr;
std::string mSearchFilter;
+ std::string mOldText;
};
#endif //LLFLOATERDEBUGSETTINGS_H
diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp
index 6e6eaa3a20..03979edbc1 100755
--- a/indra/newview/llfloaterworldmap.cpp
+++ b/indra/newview/llfloaterworldmap.cpp
@@ -169,6 +169,52 @@ public:
};
LLWorldMapHandler gWorldMapHandler;
+// handle secondlife:///app/worldmap_global/{GLOBAL_COORDS} URLs
+class LLWorldMapGlobalHandler : public LLCommandHandler
+{
+public:
+ LLWorldMapGlobalHandler() : LLCommandHandler("worldmap_global", UNTRUSTED_THROTTLE)
+ {}
+
+ virtual bool canHandleUntrusted(
+ const LLSD& params,
+ const LLSD& query_map,
+ LLMediaCtrl* web,
+ const std::string& nav_type)
+ {
+ if (nav_type == NAV_TYPE_CLICKED
+ || nav_type == NAV_TYPE_EXTERNAL)
+ {
+ // NAV_TYPE_EXTERNAL will be throttled
+ return true;
+ }
+
+ return false;
+ }
+
+ bool handle(const LLSD& params,
+ const LLSD& query_map,
+ const std::string& grid,
+ LLMediaCtrl* web)
+ {
+ if (params.size() < 3)
+ {
+ LL_WARNS() << "Correct global coordinates are not provided." << LL_ENDL;
+ return true;
+ }
+
+ LLVector3d parcel_global_pos = LLVector3d(params[0].asInteger(), params[1].asInteger(), params[2].asInteger());
+ LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance();
+ if (!parcel_global_pos.isExactlyZero() && worldmap_instance)
+ {
+ worldmap_instance->trackLocation(parcel_global_pos);
+ LLFloaterReg::showInstance("world_map", "center");
+ }
+ return true;
+ }
+};
+LLWorldMapGlobalHandler gWorldMapGlobalHandler;
+
// SocialMap handler secondlife:///app/maptrackavatar/id
class LLMapTrackAvatarHandler : public LLCommandHandler
{
diff --git a/indra/newview/llhudeffectlookat.cpp b/indra/newview/llhudeffectlookat.cpp
index d0d2ee191a..776d2dd31e 100644
--- a/indra/newview/llhudeffectlookat.cpp
+++ b/indra/newview/llhudeffectlookat.cpp
@@ -37,6 +37,7 @@
#include "lldrawable.h"
#include "llviewerobjectlist.h"
#include "llviewercontrol.h"
+#include "llvoavatarself.h"
#include "llrendersphere.h"
#include "llselectmgr.h"
#include "llglheaders.h"
@@ -397,6 +398,21 @@ bool LLHUDEffectLookAt::setLookAt(ELookAtType target_type, LLViewerObject *objec
return false;
}
+ static LLCachedControl<bool> enable_lookat_hints(gSavedSettings, "EnableLookAtTarget", true);
+ if (!enable_lookat_hints)
+ {
+ // Clear the effect so it doesn't linger around if it gets disabled
+ if (mTargetType != LOOKAT_TARGET_IDLE)
+ {
+ mTargetObject = gAgentAvatarp;
+ mTargetType = LOOKAT_TARGET_IDLE;
+ mTargetOffsetGlobal.set(2.f, 0.f, 0.f);
+ setDuration(3.f);
+ setNeedsSendToSim(true);
+ }
+ return false;
+ }
+
if (target_type >= LOOKAT_NUM_TARGETS)
{
LL_WARNS() << "Bad target_type " << (int)target_type << " - ignoring." << LL_ENDL;
@@ -409,6 +425,29 @@ bool LLHUDEffectLookAt::setLookAt(ELookAtType target_type, LLViewerObject *objec
return false;
}
+ static LLCachedControl<bool> limit_lookat_hints(gSavedSettings, "LimitLookAtTarget", true);
+ // Don't affect the look at if object is gAgentAvatarp (cursor head follow)
+ if (limit_lookat_hints && object != gAgentAvatarp)
+ {
+ // If it is a object
+ if (object)
+ {
+ position += object->getRenderPosition();
+ object = NULL;
+ }
+
+ LLVector3 agentHeadPosition = gAgentAvatarp->mHeadp->getWorldPosition();
+ float dist = (float)dist_vec(agentHeadPosition, position);
+
+ static LLCachedControl<F32> limit_lookat_hints_distance(gSavedSettings, "LimitLookAtTargetDistance", 2.0f);
+ if (dist > limit_lookat_hints_distance)
+ {
+ LLVector3 headOffset = position - agentHeadPosition;
+ headOffset *= limit_lookat_hints_distance / dist;
+ position.setVec(agentHeadPosition + headOffset);
+ }
+ }
+
F32 current_time = mTimer.getElapsedTimeF32();
// type of lookat behavior or target object has changed
diff --git a/indra/newview/llhudeffectpointat.cpp b/indra/newview/llhudeffectpointat.cpp
index eeb38cd6aa..c600010f6b 100644
--- a/indra/newview/llhudeffectpointat.cpp
+++ b/indra/newview/llhudeffectpointat.cpp
@@ -34,6 +34,7 @@
#include "llagent.h"
#include "llagentcamera.h"
#include "lldrawable.h"
+#include "llviewercontrol.h"
#include "llviewerobjectlist.h"
#include "llvoavatar.h"
#include "message.h"
@@ -226,6 +227,19 @@ bool LLHUDEffectPointAt::setPointAt(EPointAtType target_type, LLViewerObject *ob
return false;
}
+ static LLCachedControl<bool> enable_selection_hints(gSavedSettings, "EnableSelectionHints", true);
+ if (!enable_selection_hints)
+ {
+ // Clear the effect so it doesn't linger around if it gets disabled
+ if (mTargetType != POINTAT_TARGET_NONE)
+ {
+ clearPointAtTarget();
+ setDuration(1.f);
+ setNeedsSendToSim(true);
+ }
+ return false;
+ }
+
if (target_type >= POINTAT_NUM_TARGETS)
{
LL_WARNS() << "Bad target_type " << (int)target_type << " - ignoring." << LL_ENDL;
diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp
index 4c02511268..7cd0171a37 100644
--- a/indra/newview/llimprocessing.cpp
+++ b/indra/newview/llimprocessing.cpp
@@ -1520,10 +1520,10 @@ void LLIMProcessing::requestOfflineMessages()
if (!requested
&& gMessageSystem
&& !gDisconnected
- && LLMuteList::getInstance()->isLoaded()
&& isAgentAvatarValid()
&& gAgent.getRegion()
- && gAgent.getRegion()->capabilitiesReceived())
+ && gAgent.getRegion()->capabilitiesReceived()
+ && (LLMuteList::getInstance()->isLoaded() || LLMuteList::getInstance()->getLoadFailed()))
{
std::string cap_url = gAgent.getRegionCapability("ReadOfflineMsgs");
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index edefb5d109..359a009fef 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -4555,6 +4555,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
items.push_back(std::string("Rename"));
items.push_back(std::string("thumbnail"));
+ addInventoryFavoritesMenuOptions(items);
addDeleteContextMenuOptions(items, disabled_items);
// EXT-4030: disallow deletion of currently worn outfit
const LLViewerInventoryItem* base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink();
@@ -4572,6 +4573,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
EMyOutfitsSubfolderType in_my_outfits = myoutfit_object_subfolder_type(model, mUUID, outfits_id);
if (in_my_outfits != MY_OUTFITS_NO)
{
+ // Either an outfit or a subfolder inside MY_OUTFITS
if (in_my_outfits == MY_OUTFITS_SUBFOLDER)
{
// Not inside an outfit, but inside 'my outfits'
@@ -4581,6 +4583,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
items.push_back(std::string("Rename"));
items.push_back(std::string("thumbnail"));
+ addInventoryFavoritesMenuOptions(items);
addDeleteContextMenuOptions(items, disabled_items);
}
else
@@ -4629,14 +4632,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items
if (model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT) == mUUID)
{
items.push_back(std::string("Copy outfit list to clipboard"));
- if (isFavorite())
- {
- items.push_back(std::string("Remove from Favorites"));
- }
- else
- {
- items.push_back(std::string("Add to Favorites"));
- }
+ addInventoryFavoritesMenuOptions(items);
addOpenFolderMenuOptions(flags, items);
}
@@ -4898,6 +4894,18 @@ void LLFolderBridge::addOpenFolderMenuOptions(U32 flags, menuentry_vec_t& items)
}
}
+void LLFolderBridge::addInventoryFavoritesMenuOptions(menuentry_vec_t& items)
+{
+ if (isFavorite())
+ {
+ items.push_back(std::string("Remove from Favorites"));
+ }
+ else
+ {
+ items.push_back(std::string("Add to Favorites"));
+ }
+}
+
bool LLFolderBridge::hasChildren() const
{
LLInventoryModel* model = getInventoryModel();
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index ea80b6959a..d96adbd1d2 100644
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -345,6 +345,7 @@ protected:
void buildContextMenuOptions(U32 flags, menuentry_vec_t& items, menuentry_vec_t& disabled_items);
void buildContextMenuFolderOptions(U32 flags, menuentry_vec_t& items, menuentry_vec_t& disabled_items);
void addOpenFolderMenuOptions(U32 flags, menuentry_vec_t& items);
+ void addInventoryFavoritesMenuOptions(menuentry_vec_t& items); // Inventory favorites, not toolbar favorites
//--------------------------------------------------------------------
// Menu callbacks
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index a3e4f6a65d..d1fd82a7f1 100644
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -3998,15 +3998,17 @@ void LLInventoryAction::buildMarketplaceFolders(LLFolderView* root)
for (; set_iter != selected_items.end(); ++set_iter)
{
viewModel = dynamic_cast<LLFolderViewModelItemInventory *>((*set_iter)->getViewModelItem());
- if (!viewModel || !viewModel->getInventoryObject()) continue;
- if (gInventory.isObjectDescendentOf(viewModel->getInventoryObject()->getParentUUID(), marketplacelistings_id))
+ if (!viewModel) continue;
+ LLInventoryObject* inv_obj = viewModel->getInventoryObject();
+ if (!inv_obj) continue;
+ if (gInventory.isObjectDescendentOf(inv_obj->getParentUUID(), marketplacelistings_id))
{
- const LLUUID &parent_id = viewModel->getInventoryObject()->getParentUUID();
+ const LLUUID &parent_id = inv_obj->getParentUUID();
if (parent_id != marketplacelistings_id)
{
sMarketplaceFolders.push_back(parent_id);
}
- const LLUUID &curr_id = viewModel->getInventoryObject()->getUUID();
+ const LLUUID &curr_id = inv_obj->getUUID();
if (curr_id != marketplacelistings_id)
{
sMarketplaceFolders.push_back(curr_id);
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index d419f67d47..943f41b6a7 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -78,7 +78,7 @@
// Increment this if the inventory contents change in a non-backwards-compatible way.
// For viewer 2, the addition of link items makes a pre-viewer-2 cache incorrect.
-const S32 LLInventoryModel::sCurrentInvCacheVersion = 4;
+const S32 LLInventoryModel::sCurrentInvCacheVersion = 5;
bool LLInventoryModel::sFirstTimeInViewer2 = true;
S32 LLInventoryModel::sPendingSystemFolders = 0;
@@ -3384,7 +3384,7 @@ bool LLInventoryModel::loadFromFile(const std::string& filename,
}
LL_INFOS(LOG_INV) << "loading inventory from: (" << filename << ")" << LL_ENDL;
- llifstream file(filename.c_str());
+ llifstream file(filename.c_str(), std::ifstream::in | std::ifstream::binary);
if (!file.is_open())
{
@@ -3393,80 +3393,92 @@ bool LLInventoryModel::loadFromFile(const std::string& filename,
}
is_cache_obsolete = true; // Obsolete until proven current
-
- //U64 lines_count = 0U;
- std::string line;
- LLPointer<LLSDParser> parser = new LLSDNotationParser();
- while (std::getline(file, line))
+ U32 value_nbo = 0;
+ file.read((char*)&value_nbo, sizeof(U32));
+ if (file.fail())
+ {
+ LL_WARNS(LOG_INV) << "Failed to read cache version. Unable to load inventory from: " << filename << LL_ENDL;
+ }
+ else
{
- LLSD s_item;
- std::istringstream iss(line);
- if (parser->parse(iss, s_item, line.length()) == LLSDParser::PARSE_FAILURE)
+ S32 version = (S32)ntohl(value_nbo);
+ if (version == sCurrentInvCacheVersion)
{
- LL_WARNS(LOG_INV)<< "Parsing inventory cache failed" << LL_ENDL;
- break;
+ // Cache is up to date
+ is_cache_obsolete = false;
}
-
- if (s_item.has("inv_cache_version"))
+ else
{
- S32 version = s_item["inv_cache_version"].asInteger();
- if (version == sCurrentInvCacheVersion)
- {
- // Cache is up to date
- is_cache_obsolete = false;
- continue;
- }
- else
- {
- LL_WARNS(LOG_INV)<< "Inventory cache is out of date" << LL_ENDL;
- break;
- }
+ LL_WARNS(LOG_INV) << "Inventory cache is out of date" << LL_ENDL;
}
- else if (s_item.has("cat_id"))
+ }
+
+ LLSD inventory;
+ if (!is_cache_obsolete)
+ {
+ LLPointer<LLSDParser> parser = new LLSDBinaryParser();
+
+ if (parser->parse(file, inventory, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE)
{
- if (is_cache_obsolete)
- break;
+ is_cache_obsolete = true;
+ LL_WARNS(LOG_INV) << "Parsing inventory cache failed" << LL_ENDL;
+ }
+ }
- LLPointer<LLViewerInventoryCategory> inv_cat = new LLViewerInventoryCategory(LLUUID::null);
- if(inv_cat->importLLSD(s_item))
+ if (!is_cache_obsolete)
+ {
+ const LLSD& llsd_cats = inventory["categories"];
+ if (llsd_cats.isArray())
+ {
+ LLSD::array_const_iterator iter = llsd_cats.beginArray();
+ LLSD::array_const_iterator end = llsd_cats.endArray();
+ for (; iter != end; ++iter)
{
- categories.push_back(inv_cat);
+ LLPointer<LLViewerInventoryCategory> inv_cat = new LLViewerInventoryCategory(LLUUID::null);
+ if (inv_cat->importLLSDMap(*iter))
+ {
+ categories.push_back(inv_cat);
+ }
}
}
- else if (s_item.has("item_id"))
- {
- if (is_cache_obsolete)
- break;
- LLPointer<LLViewerInventoryItem> inv_item = new LLViewerInventoryItem;
- if( inv_item->fromLLSD(s_item) )
+ const LLSD& llsd_items = inventory["items"];
+ if (llsd_items.isArray())
+ {
+ LLSD::array_const_iterator iter = llsd_items.beginArray();
+ LLSD::array_const_iterator end = llsd_items.endArray();
+ for (; iter != end; ++iter)
{
- if(inv_item->getUUID().isNull())
- {
- LL_DEBUGS(LOG_INV) << "Ignoring inventory with null item id: "
- << inv_item->getName() << LL_ENDL;
- }
- else
+ LLPointer<LLViewerInventoryItem> inv_item = new LLViewerInventoryItem;
+ if (inv_item->fromLLSD(*iter))
{
- if (inv_item->getType() == LLAssetType::AT_UNKNOWN)
+ if (inv_item->getUUID().isNull())
{
- cats_to_update.insert(inv_item->getParentUUID());
+ LL_DEBUGS(LOG_INV) << "Ignoring inventory with null item id: "
+ << inv_item->getName() << LL_ENDL;
}
else
{
- items.push_back(inv_item);
+ if (inv_item->getType() == LLAssetType::AT_UNKNOWN)
+ {
+ cats_to_update.insert(inv_item->getParentUUID());
+ }
+ else
+ {
+ items.push_back(inv_item);
+ }
}
}
+
+ // TODO(brad) - figure out how to reenable this without breaking everything else
+ // static constexpr U64 BATCH_SIZE = 512U;
+ // if ((++lines_count % BATCH_SIZE) == 0)
+ // {
+ // // SL-19968 - make sure message system code gets a chance to run every so often
+ // pump_idle_startup_network();
+ // }
}
}
-
-// TODO(brad) - figure out how to reenable this without breaking everything else
-// static constexpr U64 BATCH_SIZE = 512U;
-// if ((++lines_count % BATCH_SIZE) == 0)
-// {
-// // SL-19968 - make sure message system code gets a chance to run every so often
-// pump_idle_startup_network();
-// }
}
file.close();
@@ -3489,58 +3501,54 @@ bool LLInventoryModel::saveToFile(const std::string& filename,
try
{
- llofstream fileXML(filename.c_str());
- if (!fileXML.is_open())
+ llofstream fileSD(filename.c_str(), std::ios_base::out | std::ios_base::binary);
+ if (!fileSD.is_open())
{
LL_WARNS(LOG_INV) << "Failed to open file. Unable to save inventory to: " << filename << LL_ENDL;
return false;
}
-
- LLSD cache_ver;
- cache_ver["inv_cache_version"] = sCurrentInvCacheVersion;
-
- if (fileXML.fail())
+ U32 value_nbo = htonl(sCurrentInvCacheVersion);
+ fileSD.write((const char*)(&value_nbo), sizeof(U32));
+ if (fileSD.fail())
{
- LL_WARNS(LOG_INV) << "Failed to write cache version to file. Unable to save inventory to: " << filename << LL_ENDL;
+ LL_WARNS(LOG_INV) << "Failed to write cache. Unable to save inventory to: " << filename << LL_ENDL;
return false;
}
- fileXML << LLSDOStreamer<LLSDNotationFormatter>(cache_ver) << std::endl;
+ LLSD inventory;
+ inventory["categories"] = LLSD::emptyArray();
+ LLSD& cat_array = inventory["categories"];
S32 cat_count = 0;
for (auto& cat : categories)
{
if (cat->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN)
{
- LLSD sd = LLSD::emptyMap();
+ LLSD sd;
cat->exportLLSD(sd);
- fileXML << LLSDOStreamer<LLSDNotationFormatter>(sd) << std::endl;
+ cat_array.append(sd);
cat_count++;
}
-
- if (fileXML.fail())
- {
- LL_WARNS(LOG_INV) << "Failed to write a folder to file. Unable to save inventory to: " << filename << LL_ENDL;
- return false;
- }
}
+ inventory["items"] = LLSD::emptyArray();
+ LLSD& item_array = inventory["items"];
auto it_count = items.size();
for (auto& item : items)
{
- LLSD sd = LLSD::emptyMap();
+ LLSD sd;
item->asLLSD(sd);
- fileXML << LLSDOStreamer<LLSDNotationFormatter>(sd) << std::endl;
-
- if (fileXML.fail())
- {
- LL_WARNS(LOG_INV) << "Failed to write an item to file. Unable to save inventory to: " << filename << LL_ENDL;
- return false;
- }
+ item_array.append(sd);
+ }
+ fileSD << LLSDOStreamer<LLSDBinaryFormatter>(inventory) << std::endl;
+ if (fileSD.fail())
+ {
+ LL_WARNS(LOG_INV) << "Failed to write cache. Unable to save inventory to: " << filename << LL_ENDL;
+ return false;
}
- fileXML.flush();
+ fileSD.flush();
- fileXML.close();
+ fileSD.close();
LL_INFOS(LOG_INV) << "Inventory saved: " << (S32)cat_count << " categories, " << (S32)it_count << " items." << LL_ENDL;
}
diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp
index e86599035e..9034678782 100644
--- a/indra/newview/lllogchat.cpp
+++ b/indra/newview/lllogchat.cpp
@@ -32,6 +32,8 @@
#include "lllogchat.h"
#include "llregex.h"
#include "lltrans.h"
+#include "llurlaction.h"
+#include "llurlentry.h"
#include "llviewercontrol.h"
#include "lldiriterator.h"
@@ -360,13 +362,29 @@ void LLLogChat::saveHistory(const std::string& filename,
return;
}
+ std::string altered_line = line;
+
+ // avoid costly regex calls
+ if (line.find("/mention") != std::string::npos)
+ {
+ static const boost::regex mention_regex(APP_HEADER_REGEX "/agent/[\\da-f-]+/mention", boost::regex::perl | boost::regex::icase);
+
+ // replace mention URL with [@username](URL)
+ altered_line = boost::regex_replace(line, mention_regex, [](const boost::smatch& match) -> std::string
+ {
+ std::string url = match[0].str();
+ std::string username = LLUrlAction::getURLLabel(url);
+ return "[" + username + "](" + url + ")";
+ });
+ }
+
LLSD item;
if (gSavedPerAccountSettings.getBOOL("LogTimestamp"))
item["time"] = LLLogChat::timestamp2LogString(0, gSavedPerAccountSettings.getBOOL("LogTimestampDate"));
item["from_id"] = from_id;
- item["message"] = line;
+ item["message"] = altered_line;
//adding "Second Life:" for all system messages to make chat log history parsing more reliable
if (from.empty() && from_id.isNull())
@@ -472,6 +490,19 @@ void LLLogChat::loadChatHistory(const std::string& file_name, std::list<LLSD>& m
std::string line(remove_utf8_bom(buffer));
+
+ // fast heuristic test for a mention URL in a string
+ // this is used to avoid costly regex calls
+ if (line.find("/mention)") != std::string::npos)
+ {
+ // restore original mention URL from [@username](URL) format
+ static const boost::regex altered_mention_regex("\\[@([^\\]]+)\\]\\((" APP_HEADER_REGEX "/agent/[\\da-f-]+/mention)\\)",
+ boost::regex::perl | boost::regex::icase);
+
+ // $2 captures the URL part
+ line = boost::regex_replace(line, altered_mention_regex, "$2");
+ }
+
//updated 1.23 plain text log format requires a space added before subsequent lines in a multilined message
if (' ' == line[0])
{
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 57acf51e26..07d68fc3ec 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -2380,7 +2380,13 @@ EMeshProcessingResult LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_p
LLPointer<LLVolume> volume = new LLVolume(mesh_params, LLVolumeLODGroup::getVolumeScaleFromDetail(lod));
if (volume->unpackVolumeFaces(data, data_size))
{
- if (volume->getNumFaces() > 0)
+ // Use LLVolume::getNumVolumeFaces() here and not LLVolume::getNumFaces(),
+ // because setMeshAssetLoaded() has not yet been called for this volume
+ // (it is set later in LLMeshRepository::notifyMeshLoaded()), and
+ // getNumFaces() would return the number of faces in the LLProfile
+ // instead. HB
+ S32 num_faces = volume->getNumVolumeFaces();
+ if (num_faces > 0)
{
// if we have a valid SkinInfo, cache per-joint bounding boxes for this LOD
LLPointer<LLMeshSkinInfo> skin_info = nullptr;
@@ -2394,7 +2400,7 @@ EMeshProcessingResult LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_p
}
if (skin_info.notNull() && isAgentAvatarValid())
{
- for (S32 i = 0; i < volume->getNumFaces(); ++i)
+ for (S32 i = 0; i < num_faces; ++i)
{
// NOTE: no need to lock gAgentAvatarp as the state being checked is not changed after initialization
LLVolumeFace& face = volume->getVolumeFace(i);
diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp
index 2d51acc063..f6d635f51f 100644
--- a/indra/newview/llmutelist.cpp
+++ b/indra/newview/llmutelist.cpp
@@ -154,7 +154,8 @@ std::string LLMute::getDisplayType() const
// LLMuteList()
//-----------------------------------------------------------------------------
LLMuteList::LLMuteList() :
- mIsLoaded(false)
+ mLoadState(ML_INITIAL),
+ mRequestStartTime(0.f)
{
gGenericDispatcher.addHandler("emptymutelist", &sDispatchEmptyMuteList);
@@ -209,6 +210,23 @@ bool LLMuteList::isLinden(const std::string& name)
return last_name == "linden";
}
+bool LLMuteList::getLoadFailed() const
+{
+ if (mLoadState == ML_FAILED)
+ {
+ return true;
+ }
+ if (mLoadState == ML_REQUESTED)
+ {
+ constexpr F64 WAIT_SECONDS = 30;
+ if (mRequestStartTime + WAIT_SECONDS < LLTimer::getTotalSeconds())
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
static LLVOAvatar* find_avatar(const LLUUID& id)
{
LLViewerObject *obj = gObjectList.findObject(id);
@@ -371,11 +389,14 @@ void LLMuteList::updateAdd(const LLMute& mute)
msg->addU32("MuteFlags", mute.mFlags);
gAgent.sendReliableMessage();
- if (!mIsLoaded)
+ if (!isLoaded())
{
LL_WARNS() << "Added elements to non-initialized block list" << LL_ENDL;
}
- mIsLoaded = true; // why is this here? -MG
+ // Based of logs and testing, if file doesn't exist server side,
+ // viewer will not receive any callback and won't know to set
+ // ML_LOADED. As a workaround, set it regardless of current state.
+ mLoadState = ML_LOADED;
}
@@ -564,6 +585,7 @@ bool LLMuteList::loadFromFile(const std::string& filename)
if(!filename.size())
{
LL_WARNS() << "Mute List Filename is Empty!" << LL_ENDL;
+ mLoadState = ML_FAILED;
return false;
}
@@ -571,6 +593,7 @@ bool LLMuteList::loadFromFile(const std::string& filename)
if (!fp)
{
LL_WARNS() << "Couldn't open mute list " << filename << LL_ENDL;
+ mLoadState = ML_FAILED;
return false;
}
@@ -730,13 +753,17 @@ void LLMuteList::requestFromServer(const LLUUID& agent_id)
if (gDisconnected)
{
LL_WARNS() << "Trying to request mute list when disconnected!" << LL_ENDL;
+ mLoadState = ML_FAILED;
return;
}
if (!gAgent.getRegion())
{
LL_WARNS() << "No region for agent yet, skipping mute list request!" << LL_ENDL;
+ mLoadState = ML_FAILED;
return;
}
+ mLoadState = ML_REQUESTED;
+ mRequestStartTime = LLTimer::getElapsedSeconds();
// Double amount of retries due to this request happening during busy stage
// Ideally this should be turned into a capability
gMessageSystem->sendReliable(gAgent.getRegionHost(), LL_DEFAULT_RELIABLE_RETRIES * 2, true, LL_PING_BASED_TIMEOUT_DUMMY, NULL, NULL);
@@ -749,7 +776,7 @@ void LLMuteList::requestFromServer(const LLUUID& agent_id)
void LLMuteList::cache(const LLUUID& agent_id)
{
// Write to disk even if empty.
- if(mIsLoaded)
+ if(isLoaded())
{
std::string agent_id_string;
std::string filename;
@@ -777,6 +804,13 @@ void LLMuteList::processMuteListUpdate(LLMessageSystem* msg, void**)
msg->getStringFast(_PREHASH_MuteData, _PREHASH_Filename, unclean_filename);
std::string filename = LLDir::getScrubbedFileName(unclean_filename);
+ LLMuteList* mute_list = getInstance();
+ mute_list->mLoadState = ML_REQUESTED;
+ mute_list->mRequestStartTime = LLTimer::getElapsedSeconds();
+
+ // Todo: Based of logs and testing, there is no callback
+ // from server if file doesn't exist server side.
+ // Once server side gets fixed make sure it gets handled right.
std::string *local_filename_and_path = new std::string(gDirUtilp->getExpandedFilename( LL_PATH_CACHE, filename ));
gXferManager->requestFile(*local_filename_and_path,
filename,
@@ -809,12 +843,16 @@ void LLMuteList::onFileMuteList(void** user_data, S32 error_code, LLExtStat ext_
LLMuteList::getInstance()->loadFromFile(*local_filename_and_path);
LLFile::remove(*local_filename_and_path);
}
+ else
+ {
+ LLMuteList::getInstance()->mLoadState = ML_FAILED;
+ }
delete local_filename_and_path;
}
void LLMuteList::onAccountNameChanged(const LLUUID& id, const std::string& username)
{
- if (mIsLoaded)
+ if (isLoaded())
{
LLMute mute(id, username, LLMute::AGENT);
mute_set_t::iterator mute_it = mMutes.find(mute);
@@ -866,7 +904,7 @@ void LLMuteList::removeObserver(LLMuteListObserver* observer)
void LLMuteList::setLoaded()
{
- mIsLoaded = true;
+ mLoadState = ML_LOADED;
notifyObservers();
}
diff --git a/indra/newview/llmutelist.h b/indra/newview/llmutelist.h
index 13d579c61f..b65fd61fcc 100644
--- a/indra/newview/llmutelist.h
+++ b/indra/newview/llmutelist.h
@@ -74,6 +74,14 @@ class LLMuteList : public LLSingleton<LLMuteList>
LLSINGLETON(LLMuteList);
~LLMuteList();
/*virtual*/ void cleanupSingleton() override;
+
+ enum EMuteListState
+ {
+ ML_INITIAL,
+ ML_REQUESTED,
+ ML_LOADED,
+ ML_FAILED,
+ };
public:
// reasons for auto-unmuting a resident
enum EAutoReason
@@ -107,7 +115,8 @@ public:
static bool isLinden(const std::string& name);
- bool isLoaded() const { return mIsLoaded; }
+ bool isLoaded() const { return mLoadState == ML_LOADED; }
+ bool getLoadFailed() const;
std::vector<LLMute> getMutes() const;
@@ -167,7 +176,8 @@ private:
typedef std::set<LLMuteListObserver*> observer_set_t;
observer_set_t mObservers;
- bool mIsLoaded;
+ EMuteListState mLoadState;
+ F64 mRequestStartTime;
friend class LLDispatchEmptyMuteList;
};
diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp
index 2b2b5ea696..cb2a6191fa 100644
--- a/indra/newview/lloutfitslist.cpp
+++ b/indra/newview/lloutfitslist.cpp
@@ -34,11 +34,13 @@
#include "llaccordionctrl.h"
#include "llaccordionctrltab.h"
#include "llagentwearables.h"
+#include "llaisapi.h"
#include "llappearancemgr.h"
#include "llappviewer.h"
#include "llfloaterreg.h"
#include "llfloatersidepanelcontainer.h"
#include "llinspecttexture.h"
+#include "llinventorymodelbackgroundfetch.h"
#include "llinventoryfunctions.h"
#include "llinventorymodel.h"
#include "llmenubutton.h"
@@ -247,12 +249,22 @@ void LLOutfitsList::updateAddedCategory(LLUUID cat_id)
list->setRightMouseDownCallback(boost::bind(&LLOutfitsList::onWearableItemsListRightClick, this, _1, _2, _3));
- // Fetch the new outfit contents.
- cat->fetch();
-
- // Refresh the list of outfit items after fetch().
- // Further list updates will be triggered by the category observer.
- list->updateList(cat_id);
+ if (AISAPI::isAvailable() && LLInventoryModelBackgroundFetch::instance().folderFetchActive())
+ {
+ // for reliability just fetch it whole, linked items included
+ LLInventoryModelBackgroundFetch::instance().fetchFolderAndLinks(cat_id, [cat_id, list]
+ {
+ if (list) list->updateList(cat_id);
+ });
+ }
+ else
+ {
+ // Fetch the new outfit contents.
+ cat->fetch();
+ // Refresh the list of outfit items after fetch().
+ // Further list updates will be triggered by the category observer.
+ list->updateList(cat_id);
+ }
// If filter is currently applied we store the initial tab state.
if (!getFilterSubString().empty())
diff --git a/indra/newview/llpanelemojicomplete.cpp b/indra/newview/llpanelemojicomplete.cpp
index 3a6a6a5ec3..f0555408dd 100644
--- a/indra/newview/llpanelemojicomplete.cpp
+++ b/indra/newview/llpanelemojicomplete.cpp
@@ -463,6 +463,7 @@ void LLPanelEmojiComplete::updateConstraints()
{
mEmojiHeight = mRenderRect.getHeight();
mRenderRect.stretch((mRenderRect.getWidth() - static_cast<S32>(mVisibleEmojis) * mEmojiWidth) / -2, 0);
+ mRenderRect.translate(-mRenderRect.mLeft, 0); // Left align emojis to fix hitboxes
}
updateScrollPos();
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index 4909c11bae..514d772340 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -2205,7 +2205,7 @@ void LLPanelFace::refreshMedia()
// check if all faces have media(or, all dont have media)
- LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo = selected_objects->getSelectedTEValue(&func, bool_has_media);
+ bool identical_has_media_info = selected_objects->getSelectedTEValue(&func, bool_has_media);
const LLMediaEntry default_media_data;
@@ -2227,7 +2227,8 @@ void LLPanelFace::refreshMedia()
} func_media_data(default_media_data);
LLMediaEntry media_data_get;
- LLFloaterMediaSettings::getInstance()->mMultipleMedia = !(selected_objects->getSelectedTEValue(&func_media_data, media_data_get));
+ bool multiple_media = !(selected_objects->getSelectedTEValue(&func_media_data, media_data_get));
+ bool multiple_valid_media = false;
std::string multi_media_info_str = LLTrans::getString("Multiple Media");
std::string media_title = "";
@@ -2236,12 +2237,12 @@ void LLPanelFace::refreshMedia()
mAddMedia->setEnabled(editable);
// IF all the faces have media (or all dont have media)
- if (LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo)
+ if (identical_has_media_info)
{
// TODO: get media title and set it.
mTitleMediaText->clear();
// if identical is set, all faces are same (whether all empty or has the same media)
- if (!(LLFloaterMediaSettings::getInstance()->mMultipleMedia))
+ if (!multiple_media)
{
// Media data is valid
if (media_data_get != default_media_data)
@@ -2262,9 +2263,9 @@ void LLPanelFace::refreshMedia()
else // not all face has media but at least one does.
{
// seleted faces have not identical value
- LLFloaterMediaSettings::getInstance()->mMultipleValidMedia = selected_objects->isMultipleTEValue(&func_media_data, default_media_data);
+ multiple_valid_media = selected_objects->isMultipleTEValue(&func_media_data, default_media_data);
- if (LLFloaterMediaSettings::getInstance()->mMultipleValidMedia)
+ if (multiple_valid_media)
{
media_title = multi_media_info_str;
}
@@ -2301,7 +2302,7 @@ void LLPanelFace::refreshMedia()
// load values for media settings
updateMediaSettings();
- LLFloaterMediaSettings::initValues(mMediaSettings, editable);
+ LLFloaterMediaSettings::initValues(mMediaSettings, editable, identical_has_media_info, multiple_media, multiple_valid_media);
}
void LLPanelFace::unloadMedia()
@@ -3374,6 +3375,7 @@ void LLPanelFace::onSelectNormalTexture(const LLSD& data)
// TODO: test if there is media on the item and only allow editing if present
void LLPanelFace::onClickBtnEditMedia()
{
+ LLFloaterMediaSettings::getInstance(); // make sure floater we are about to open exists before refreshMedia
refreshMedia();
LLFloaterReg::showInstance("media_settings");
}
@@ -3392,6 +3394,7 @@ void LLPanelFace::onClickBtnAddMedia()
// check if multiple faces are selected
if (LLSelectMgr::getInstance()->getSelection()->isMultipleTESelected())
{
+ LLFloaterMediaSettings::getInstance(); // make sure floater we are about to open exists before refreshMedia
refreshMedia();
LLNotificationsUtil::add("MultipleFacesSelected", LLSD(), LLSD(), multipleFacesSelectedConfirm);
}
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index ed80c8b732..59aa375457 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -184,7 +184,6 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
mCallback(callback),
mCallbackData(cb_data),
mListener(new LLPanelLoginListener(this)),
- mFirstLoginThisInstall(gSavedSettings.getBOOL("FirstLoginThisInstall")),
mUsernameLength(0),
mPasswordLength(0),
mLocationLength(0),
@@ -203,14 +202,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
login_holder->addChild(this);
}
- if (mFirstLoginThisInstall)
- {
- buildFromFile( "panel_login_first.xml");
- }
- else
- {
- buildFromFile( "panel_login.xml");
- }
+ buildFromFile("panel_login.xml");
reshape(rect.getWidth(), rect.getHeight());
@@ -224,38 +216,36 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
sendChildToBack(getChildView("sign_up_text"));
std::string current_grid = LLGridManager::getInstance()->getGrid();
- if (!mFirstLoginThisInstall)
- {
- LLComboBox* favorites_combo = getChild<LLComboBox>("start_location_combo");
- updateLocationSelectorsVisibility(); // separate so that it can be called from preferences
- favorites_combo->setReturnCallback(boost::bind(&LLPanelLogin::onClickConnect, false));
- favorites_combo->setFocusLostCallback(boost::bind(&LLPanelLogin::onLocationSLURL, this));
- LLComboBox* server_choice_combo = getChild<LLComboBox>("server_combo");
- server_choice_combo->setCommitCallback(boost::bind(&LLPanelLogin::onSelectServer, this));
+ LLComboBox* favorites_combo = getChild<LLComboBox>("start_location_combo");
+ updateLocationSelectorsVisibility(); // separate so that it can be called from preferences
+ favorites_combo->setReturnCallback(boost::bind(&LLPanelLogin::onClickConnect, false));
+ favorites_combo->setFocusLostCallback(boost::bind(&LLPanelLogin::onLocationSLURL, this));
+
+ LLComboBox* server_choice_combo = getChild<LLComboBox>("server_combo");
+ server_choice_combo->setCommitCallback(boost::bind(&LLPanelLogin::onSelectServer, this));
- // Load all of the grids, sorted, and then add a bar and the current grid at the top
- server_choice_combo->removeall();
+ // Load all of the grids, sorted, and then add a bar and the current grid at the top
+ server_choice_combo->removeall();
- std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids();
- for (std::map<std::string, std::string>::iterator grid_choice = known_grids.begin();
- grid_choice != known_grids.end();
- grid_choice++)
+ std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids();
+ for (std::map<std::string, std::string>::iterator grid_choice = known_grids.begin();
+ grid_choice != known_grids.end();
+ grid_choice++)
+ {
+ if (!grid_choice->first.empty() && current_grid != grid_choice->first)
{
- if (!grid_choice->first.empty() && current_grid != grid_choice->first)
- {
- LL_DEBUGS("AppInit") << "adding " << grid_choice->first << LL_ENDL;
- server_choice_combo->add(grid_choice->second, grid_choice->first);
- }
+ LL_DEBUGS("AppInit") << "adding " << grid_choice->first << LL_ENDL;
+ server_choice_combo->add(grid_choice->second, grid_choice->first);
}
- server_choice_combo->sortByName();
-
- LL_DEBUGS("AppInit") << "adding current " << current_grid << LL_ENDL;
- server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(),
- current_grid,
- ADD_TOP);
- server_choice_combo->selectFirstItem();
}
+ server_choice_combo->sortByName();
+
+ LL_DEBUGS("AppInit") << "adding current " << current_grid << LL_ENDL;
+ server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(),
+ current_grid,
+ ADD_TOP);
+ server_choice_combo->selectFirstItem();
LLSLURL start_slurl(LLStartUp::getStartSLURL());
// The StartSLURL might have been set either by an explicit command-line
@@ -331,15 +321,6 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
void LLPanelLogin::addFavoritesToStartLocation()
{
- if (mFirstLoginThisInstall)
- {
- // first login panel has no favorites, just update name length and buttons
- std::string user_defined_name = getChild<LLComboBox>("username_combo")->getSimple();
- mUsernameLength = static_cast<unsigned int>(user_defined_name.length());
- updateLoginButtons();
- return;
- }
-
// Clear the combo.
LLComboBox* combo = getChild<LLComboBox>("start_location_combo");
if (!combo) return;
@@ -559,16 +540,9 @@ void LLPanelLogin::resetFields()
// function is used to reset list in case of changes by external sources
return;
}
- if (sInstance->mFirstLoginThisInstall)
- {
- // no list to populate
- LL_WARNS() << "Shouldn't happen, user should have no ability to modify list on first install" << LL_ENDL;
- }
- else
- {
- LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid());
- sInstance->populateUserList(cred);
- }
+
+ LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid());
+ sInstance->populateUserList(cred);
}
// static
@@ -586,7 +560,6 @@ void LLPanelLogin::setFields(LLPointer<LLCredential> credential)
if(identifier.has("type") && (std::string)identifier["type"] == "agent")
{
- // not nessesary for panel_login.xml, needed for panel_login_first.xml
std::string firstname = identifier["first_name"].asString();
std::string lastname = identifier["last_name"].asString();
std::string login_id = firstname;
@@ -1081,8 +1054,7 @@ void LLPanelLogin::onRememberUserCheck(void*)
LLComboBox* user_combo(sInstance->getChild<LLComboBox>("username_combo"));
bool remember = remember_name->getValue().asBoolean();
- if (!sInstance->mFirstLoginThisInstall
- && user_combo->getCurrentIndex() != -1
+ if (user_combo->getCurrentIndex() != -1
&& !remember)
{
remember = true;
@@ -1197,17 +1169,14 @@ void LLPanelLogin::updateLoginButtons()
login_btn->setEnabled(mUsernameLength != 0 && mPasswordLength != 0);
- if (!mFirstLoginThisInstall)
+ LLComboBox* user_combo = getChild<LLComboBox>("username_combo");
+ LLCheckBoxCtrl* remember_name = getChild<LLCheckBoxCtrl>("remember_name");
+ if (user_combo->getCurrentIndex() != -1)
{
- LLComboBox* user_combo = getChild<LLComboBox>("username_combo");
- LLCheckBoxCtrl* remember_name = getChild<LLCheckBoxCtrl>("remember_name");
- if (user_combo->getCurrentIndex() != -1)
- {
- remember_name->setValue(true);
- LLCheckBoxCtrl* remember_pass = getChild<LLCheckBoxCtrl>("remember_password");
- remember_pass->setEnabled(true);
- } // Note: might be good idea to do "else remember_name->setValue(mRememberedState)" but it might behave 'weird' to user
- }
+ remember_name->setValue(true);
+ LLCheckBoxCtrl* remember_pass = getChild<LLCheckBoxCtrl>("remember_password");
+ remember_pass->setEnabled(true);
+ } // Note: might be good idea to do "else remember_name->setValue(mRememberedState)" but it might behave 'weird' to user
}
void LLPanelLogin::populateUserList(LLPointer<LLCredential> credential)
diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h
index a1bf25fb05..1259bf26d6 100644
--- a/indra/newview/llpanellogin.h
+++ b/indra/newview/llpanellogin.h
@@ -119,7 +119,6 @@ private:
static LLPanelLogin* sInstance;
static bool sCapslockDidNotification;
- bool mFirstLoginThisInstall;
static bool sCredentialSet;
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index 01541968de..42c40fe404 100644
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -846,7 +846,7 @@ void LLPanelPeople::updateNearbyList()
mNearbyList->setDirty();
#ifdef LL_DISCORD
if (gSavedSettings.getBOOL("EnableDiscord"))
- LLAppViewer::updateDiscordPartyMaxSize(mNearbyList->getIDs().size());
+ LLAppViewer::updateDiscordPartyMaxSize((S32)mNearbyList->getIDs().size());
#endif
DISTANCE_COMPARATOR.updateAvatarsPositions(positions, mNearbyList->getIDs());
diff --git a/indra/newview/llpanelpeoplemenus.cpp b/indra/newview/llpanelpeoplemenus.cpp
index 6966cb38ab..794ae4ad44 100644
--- a/indra/newview/llpanelpeoplemenus.cpp
+++ b/indra/newview/llpanelpeoplemenus.cpp
@@ -155,11 +155,15 @@ void PeopleContextMenu::buildContextMenu(class LLMenuGL& menu, U32 flags)
bool PeopleContextMenu::enableContextMenuItem(const LLSD& userdata)
{
+ std::string item = userdata.asString();
if(gAgent.getID() == mUUIDs.front())
{
+ if (item == std::string("can_zoom_in"))
+ {
+ return true;
+ }
return false;
}
- std::string item = userdata.asString();
// Note: can_block and can_delete is used only for one person selected menu
// so we don't need to go over all uuids.
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 1948bba4be..00c219fdda 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -2249,6 +2249,7 @@ void LLSelectMgr::selectionRevertGLTFMaterials()
{
// Restore base material
LLUUID asset_id = nodep->mSavedGLTFMaterialIds[te];
+ LLUUID old_asset_id = objectp->getRenderMaterialID(te);
// Update material locally
objectp->setRenderMaterialID(te, asset_id, false /*wait for LLGLTFMaterialList update*/);
@@ -2259,18 +2260,29 @@ void LLSelectMgr::selectionRevertGLTFMaterials()
objectp->setTEGLTFMaterialOverride(te, material);
}
- // Enqueue update to server
- if (asset_id.notNull() && material)
+ if (asset_id.isNull() || !material)
+ {
+ //blank override out
+ LLGLTFMaterialList::queueApply(objectp, te, asset_id);
+ }
+ if (old_asset_id != asset_id)
{
// Restore overrides and base material
+ // Note: might not work reliably if asset is already there, might
+ // have a server sided problem where servers applies override
+ // first then resets it by adding asset, in which case need
+ // to create a server ticket and chain asset then override
+ // application.
LLGLTFMaterialList::queueApply(objectp, te, asset_id, material);
}
else
{
- //blank override out
- LLGLTFMaterialList::queueApply(objectp, te, asset_id);
+ // Enqueue override update to server
+ // Note: this is suboptimal, better to send asset id as well
+ // but there seems to be a server problem with queueApply
+ // that ignores override in some cases
+ LLGLTFMaterialList::queueModify(objectp, te, material);
}
-
}
return true;
}
diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp
index 12a9d5e9b7..b49c0119ed 100644
--- a/indra/newview/llspeakers.cpp
+++ b/indra/newview/llspeakers.cpp
@@ -1028,7 +1028,7 @@ void LLLocalSpeakerMgr::updateSpeakerList()
LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, gAgent.getPositionGlobal(), CHAT_NORMAL_RADIUS);
#ifdef LL_DISCORD
if (gSavedSettings.getBOOL("EnableDiscord"))
- LLAppViewer::updateDiscordPartyCurrentSize(avatar_ids.size());
+ LLAppViewer::updateDiscordPartyCurrentSize((S32)avatar_ids.size());
#endif
for(U32 i=0; i<avatar_ids.size(); i++)
{
diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp
index bda75c16e7..bf4ec14487 100644
--- a/indra/newview/llstatusbar.cpp
+++ b/indra/newview/llstatusbar.cpp
@@ -115,6 +115,8 @@ LLStatusBar::LLStatusBar(const LLRect& rect)
mBtnVolume(NULL),
mBoxBalance(NULL),
mBalance(0),
+ mBalanceClicked(false),
+ mObscureBalance(false),
mHealth(100),
mSquareMetersCredit(0),
mSquareMetersCommitted(0),
@@ -126,8 +128,6 @@ LLStatusBar::LLStatusBar(const LLRect& rect)
// status bar can possible overlay menus?
setMouseOpaque(false);
- mBalanceTimer = new LLFrameTimer();
- mHealthTimer = new LLFrameTimer();
mFpsUpdateTimer = new LLFrameTimer();
buildFromFile("panel_status_bar.xml");
@@ -135,12 +135,6 @@ LLStatusBar::LLStatusBar(const LLRect& rect)
LLStatusBar::~LLStatusBar()
{
- delete mBalanceTimer;
- mBalanceTimer = NULL;
-
- delete mHealthTimer;
- mHealthTimer = NULL;
-
// LLView destructor cleans up children
}
@@ -176,7 +170,8 @@ bool LLStatusBar::postBuild()
getChild<LLUICtrl>("goShop")->setCommitCallback(boost::bind(&LLWeb::loadURL, gSavedSettings.getString("MarketplaceURL"), LLStringUtil::null, LLStringUtil::null));
mBoxBalance = getChild<LLTextBox>("balance");
- mBoxBalance->setClickedCallback( &LLStatusBar::onClickBalance, this );
+ mBoxBalance->setClickedCallback(&LLStatusBar::onClickRefreshBalance, this);
+ mBoxBalance->setDoubleClickCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { onClickToggleBalance(); });
mIconPresetsCamera = getChild<LLIconCtrl>( "presets_icon_camera" );
mIconPresetsCamera->setMouseEnterCallback(boost::bind(&LLStatusBar::onMouseEnterPresetsCamera, this));
@@ -196,12 +191,14 @@ bool LLStatusBar::postBuild()
gSavedSettings.getControl("MuteAudio")->getSignal()->connect(boost::bind(&LLStatusBar::onVolumeChanged, this, _2));
gSavedSettings.getControl("EnableVoiceChat")->getSignal()->connect(boost::bind(&LLStatusBar::onVoiceChanged, this, _2));
+ gSavedSettings.getControl("ObscureBalanceInStatusBar")->getSignal()->connect(boost::bind(&LLStatusBar::onObscureBalanceChanged, this, _2));
if (!gSavedSettings.getBOOL("EnableVoiceChat") && LLAppViewer::instance()->isSecondInstance())
{
// Indicate that second instance started without sound
mBtnVolume->setImageUnselected(LLUI::getUIImage("VoiceMute_Off"));
}
+ mObscureBalance = gSavedSettings.getBOOL("ObscureBalanceInStatusBar");
// Adding Net Stat Graph
S32 x = getRect().getWidth() - 2;
@@ -334,6 +331,12 @@ void LLStatusBar::refresh()
mTextTime->setToolTip (dtStr);
}
+ if (mBalanceClicked && mBalanceClickTimer.getElapsedTimeF32() > 1.f)
+ {
+ mBalanceClicked = false;
+ sendMoneyBalanceRequest();
+ }
+
LLRect r;
const S32 MENU_RIGHT = gMenuBarView->getRightmostMenuEdge();
@@ -399,9 +402,17 @@ void LLStatusBar::setBalance(S32 balance)
std::string money_str = LLResMgr::getInstance()->getMonetaryString( balance );
LLStringUtil::format_map_t string_args;
- string_args["[AMT]"] = llformat("%s", money_str.c_str());
+ if (mObscureBalance)
+ {
+ string_args["[AMT]"] = "****";
+ }
+ else
+ {
+ string_args["[AMT]"] = llformat("%s", money_str.c_str());
+ }
std::string label_str = getString("buycurrencylabel", string_args);
mBoxBalance->setValue(label_str);
+ mBoxBalance->setToolTipArg(LLStringExplicit("[AMT]"), llformat("%s", money_str.c_str()));
updateBalancePanelPosition();
@@ -421,8 +432,6 @@ void LLStatusBar::setBalance(S32 balance)
if( balance != mBalance )
{
- mBalanceTimer->reset();
- mBalanceTimer->setTimerExpirySec( ICON_TIMER_EXPIRY );
mBalance = balance;
}
}
@@ -474,9 +483,6 @@ void LLStatusBar::setHealth(S32 health)
}
}
}
-
- mHealthTimer->reset();
- mHealthTimer->setTimerExpirySec( ICON_TIMER_EXPIRY );
}
mHealth = health;
@@ -636,13 +642,27 @@ static void onClickVolume(void* data)
}
//static
-void LLStatusBar::onClickBalance(void* )
+void LLStatusBar::onClickRefreshBalance(void* data)
{
- // Force a balance request message:
- LLStatusBar::sendMoneyBalanceRequest();
+ LLStatusBar* status_bar = (LLStatusBar*)data;
+
+ if (!status_bar->mBalanceClicked)
+ {
+ // Schedule a balance request message:
+ status_bar->mBalanceClicked = true;
+ status_bar->mBalanceClickTimer.reset();
+ }
// The refresh of the display (call to setBalance()) will be done by process_money_balance_reply()
}
+void LLStatusBar::onClickToggleBalance()
+{
+ mObscureBalance = !mObscureBalance;
+ gSavedSettings.setBOOL("ObscureBalanceInStatusBar", mObscureBalance);
+ setBalance(mBalance);
+ mBalanceClicked = false; // supress click
+}
+
//static
void LLStatusBar::onClickMediaToggle(void* data)
{
@@ -678,6 +698,12 @@ void LLStatusBar::onVoiceChanged(const LLSD& newvalue)
refresh();
}
+void LLStatusBar::onObscureBalanceChanged(const LLSD& newvalue)
+{
+ mObscureBalance = newvalue.asBoolean();
+ setBalance(mBalance);
+}
+
void LLStatusBar::onUpdateFilterTerm()
{
LLWString searchValue = utf8str_to_wstring( mFilterEdit->getValue() );
diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h
index 86c1ccd051..f1225a22f8 100644
--- a/indra/newview/llstatusbar.h
+++ b/indra/newview/llstatusbar.h
@@ -72,7 +72,8 @@ public:
void debitBalance(S32 debit);
void creditBalance(S32 credit);
- // Request the latest currency balance from the server
+ // Request the latest currency balance from the server.
+ // Reply at process_money_balance_reply()
static void sendMoneyBalanceRequest();
void setHealth(S32 percent);
@@ -102,6 +103,7 @@ private:
void onClickBuyCurrency();
void onVolumeChanged(const LLSD& newvalue);
void onVoiceChanged(const LLSD& newvalue);
+ void onObscureBalanceChanged(const LLSD& newvalue);
void onMouseEnterPresetsCamera();
void onMouseEnterPresets();
@@ -109,7 +111,8 @@ private:
void onMouseEnterNearbyMedia();
static void onClickMediaToggle(void* data);
- static void onClickBalance(void* data);
+ static void onClickRefreshBalance(void* data);
+ void onClickToggleBalance();
static void onClickFps(void* data);
@@ -139,11 +142,12 @@ private:
LLFrameTimer *mFpsUpdateTimer;
S32 mBalance;
+ bool mBalanceClicked;
+ bool mObscureBalance;
+ LLTimer mBalanceClickTimer;
S32 mHealth;
S32 mSquareMetersCredit;
S32 mSquareMetersCommitted;
- LLFrameTimer* mBalanceTimer;
- LLFrameTimer* mHealthTimer;
LLPanelPresetsCameraPulldown* mPanelPresetsCameraPulldown;
LLPanelPresetsPulldown* mPanelPresetsPulldown;
LLPanelVolumePulldown* mPanelVolumePulldown;
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index 3665ff5e87..b4a5955be3 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -1125,28 +1125,33 @@ void set_texture_to_material(LLViewerObject* hit_obj,
case LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR:
default:
{
- material->setBaseColorId(asset_id);
+ material->setBaseColorId(asset_id, true);
}
break;
case LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS:
{
- material->setOcclusionRoughnessMetallicId(asset_id);
+ material->setOcclusionRoughnessMetallicId(asset_id, true);
}
break;
case LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE:
{
- material->setEmissiveId(asset_id);
+ material->setEmissiveId(asset_id, true);
}
break;
case LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL:
{
- material->setNormalId(asset_id);
+ material->setNormalId(asset_id, true);
}
break;
}
+ // Update viewer side, needed for updating mSavedGLTFOverrideMaterials.
+ // Also for parity, we are immediately setting textures and materials,
+ // so we should immediate set overrides to.
+ hit_obj->setTEGLTFMaterialOverride(hit_face, material);
+ // update server
LLGLTFMaterialList::queueModify(hit_obj, hit_face, material);
}
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index 5f61aeaf13..6155058f14 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -761,18 +761,23 @@ void LLViewerInventoryCategory::exportLLSD(LLSD & cat_data) const
cat_data[INV_VERSION] = mVersion;
}
-bool LLViewerInventoryCategory::importLLSD(const LLSD& cat_data)
+bool LLViewerInventoryCategory::importLLSD(const std::string& label, const LLSD& value)
{
- LLInventoryCategory::importLLSD(cat_data);
- if (cat_data.has(INV_OWNER_ID))
+ if (LLInventoryCategory::importLLSD(label, value))
{
- mOwnerID = cat_data[INV_OWNER_ID].asUUID();
+ return true;
}
- if (cat_data.has(INV_VERSION))
+ else if (label == INV_OWNER_ID)
{
- setVersion(cat_data[INV_VERSION].asInteger());
+ mOwnerID = value.asUUID();
+ return true;
}
- return true;
+ else if (label == INV_VERSION)
+ {
+ setVersion(value.asInteger());
+ return true;
+ }
+ return false;
}
bool LLViewerInventoryCategory::acceptItem(LLInventoryItem* inv_item)
diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h
index 5cd31353f8..0dfbf0cced 100644
--- a/indra/newview/llviewerinventory.h
+++ b/indra/newview/llviewerinventory.h
@@ -233,7 +233,7 @@ public:
S32 getViewerDescendentCount() const;
virtual void exportLLSD(LLSD &sd) const;
- virtual bool importLLSD(const LLSD& cat_data);
+ virtual bool importLLSD(const std::string& label, const LLSD& value);
void determineFolderType();
void changeType(LLFolderType::EType new_folder_type);
diff --git a/indra/newview/llviewermedia_streamingaudio.cpp b/indra/newview/llviewermedia_streamingaudio.cpp
index 21f5ba64d7..959de38364 100644
--- a/indra/newview/llviewermedia_streamingaudio.cpp
+++ b/indra/newview/llviewermedia_streamingaudio.cpp
@@ -61,13 +61,26 @@ void LLStreamingAudio_MediaPlugins::start(const std::string& url)
if(!mMediaPlugin)
return;
- if (!url.empty()) {
+ if (!url.empty())
+ {
LL_INFOS() << "Starting internet stream: " << url << LL_ENDL;
- mURL = url;
- mMediaPlugin->loadURI ( url );
+
+ mURL = url; // keep original url here for comparison purposes
+ std::string snt_url = url;
+ LLStringUtil::trim(snt_url);
+ size_t pos = snt_url.find(' ');
+ if (pos != std::string::npos)
+ {
+ // fmod permited having names after the url and people were using it.
+ // People label their streams this way, ignore the 'label'.
+ snt_url = snt_url.substr(0, pos);
+ }
+ mMediaPlugin->loadURI(snt_url);
mMediaPlugin->start();
LL_INFOS() << "Playing stream..." << LL_ENDL;
- } else {
+ }
+ else
+ {
LL_INFOS() << "setting stream to NULL"<< LL_ENDL;
mURL.clear();
mMediaPlugin->stop();
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index d9d20611b4..3695478061 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -69,6 +69,7 @@
#include "llviewerassetupload.h"
// linden libraries
+#include "llfilesystem.h"
#include "llnotificationsutil.h"
#include "llsdserialize.h"
#include "llsdutil.h"
@@ -550,16 +551,9 @@ void do_bulk_upload(std::vector<std::string> filenames, bool allow_2k)
if (LLResourceUploadInfo::findAssetTypeAndCodecOfExtension(ext, asset_type, codec))
{
bool resource_upload = false;
- if (asset_type == LLAssetType::AT_TEXTURE && allow_2k)
+ if (asset_type == LLAssetType::AT_TEXTURE)
{
- LLPointer<LLImageFormatted> image_frmted = LLImageFormatted::createFromType(codec);
- if (gDirUtilp->fileExists(filename) && image_frmted && image_frmted->load(filename))
- {
- S32 biased_width = LLImageRaw::biasedDimToPowerOfTwo(image_frmted->getWidth(), LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
- S32 biased_height = LLImageRaw::biasedDimToPowerOfTwo(image_frmted->getHeight(), LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
- expected_upload_cost = LLAgentBenefitsMgr::current().getTextureUploadCost(biased_width, biased_height);
- resource_upload = true;
- }
+ resource_upload = true;
}
else if (LLAgentBenefitsMgr::current().findUploadCost(asset_type, expected_upload_cost))
{
@@ -568,23 +562,115 @@ void do_bulk_upload(std::vector<std::string> filenames, bool allow_2k)
if (resource_upload)
{
- LLNewFileResourceUploadInfo* info_p = new LLNewFileResourceUploadInfo(
- filename,
- asset_name,
- asset_name, 0,
- LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
- LLFloaterPerms::getNextOwnerPerms("Uploads"),
- LLFloaterPerms::getGroupPerms("Uploads"),
- LLFloaterPerms::getEveryonePerms("Uploads"),
- expected_upload_cost);
-
- if (!allow_2k)
+ if (asset_type == LLAssetType::AT_TEXTURE)
{
- info_p->setMaxImageSize(1024);
- }
- LLResourceUploadInfo::ptr_t uploadInfo(info_p);
+ std::string exten = gDirUtilp->getExtension(filename);
+ U32 codec = LLImageBase::getCodecFromExtension(exten);
+
+ // Load the image
+ LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
+ if (image.isNull())
+ {
+ LL_WARNS() << "Failed to create image container for " << filename << LL_ENDL;
+ continue;
+ }
+ if (!image->load(filename))
+ {
+ LL_WARNS() << "Failed to load image: " << filename << LL_ENDL;
+ continue;
+ }
+ // Decompress or expand it in a raw image structure
+ LLPointer<LLImageRaw> raw_image = new LLImageRaw;
+ if (!image->decode(raw_image, 0.0f))
+ {
+ LL_WARNS() << "Failed to decode image: " << filename << LL_ENDL;
+ continue;
+ }
+ // Check the image constraints
+ if ((image->getComponents() != 3) && (image->getComponents() != 4))
+ {
+ LL_WARNS() << "Attempted to upload a texture that has " << image->getComponents()
+ << " components, but only 3 (RGB) or 4 (RGBA) are allowed." << LL_ENDL;
+ continue;
+ }
+ // Downscale images to fit the max_texture_dimensions_*, or 1024 if allow_2k is false
+ S32 max_width = allow_2k ? gSavedSettings.getS32("max_texture_dimension_X") : 1024;
+ S32 max_height = allow_2k ? gSavedSettings.getS32("max_texture_dimension_Y") : 1024;
+
+ S32 orig_width = raw_image->getWidth();
+ S32 orig_height = raw_image->getHeight();
+
+ if (orig_width > max_width || orig_height > max_height)
+ {
+ // Calculate scale factors
+ F32 width_scale = (F32)max_width / (F32)orig_width;
+ F32 height_scale = (F32)max_height / (F32)orig_height;
+ F32 scale = llmin(width_scale, height_scale);
+
+ // Calculate new dimensions, preserving aspect ratio
+ S32 new_width = LLImageRaw::contractDimToPowerOfTwo(llclamp((S32)llroundf(orig_width * scale), 4, max_width));
+ S32 new_height = LLImageRaw::contractDimToPowerOfTwo(llclamp((S32)llroundf(orig_height * scale), 4, max_height));
+
+ if (!raw_image->scale(new_width, new_height))
+ {
+ LL_WARNS() << "Failed to scale image from " << orig_width << "x" << orig_height << " to " << new_width << "x"
+ << new_height << LL_ENDL;
+ continue;
+ }
+
+ // Inform the resident about the resized image
+ LLSD subs;
+ subs["[ORIGINAL_WIDTH]"] = orig_width;
+ subs["[ORIGINAL_HEIGHT]"] = orig_height;
+ subs["[NEW_WIDTH]"] = new_width;
+ subs["[NEW_HEIGHT]"] = new_height;
+ subs["[MAX_WIDTH]"] = max_width;
+ subs["[MAX_HEIGHT]"] = max_height;
+ LLNotificationsUtil::add("ImageUploadResized", subs);
+ }
+
+ raw_image->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
+
+ LLTransactionID tid;
+ tid.generate();
+ LLAssetID new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
- upload_new_resource(uploadInfo);
+ LLPointer<LLImageJ2C> formatted = new LLImageJ2C;
+
+ if (formatted->encode(raw_image, 0.0f))
+ {
+ LLFileSystem fmt_file(new_asset_id, LLAssetType::AT_TEXTURE, LLFileSystem::WRITE);
+ fmt_file.write(formatted->getData(), formatted->getDataSize());
+
+ LLResourceUploadInfo::ptr_t assetUploadInfo(new LLResourceUploadInfo(
+ tid, LLAssetType::AT_TEXTURE,
+ asset_name,
+ asset_name, 0,
+ LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
+ LLFloaterPerms::getNextOwnerPerms("Uploads"),
+ LLFloaterPerms::getGroupPerms("Uploads"),
+ LLFloaterPerms::getEveryonePerms("Uploads"),
+ LLAgentBenefitsMgr::current().getTextureUploadCost(raw_image->getWidth(), raw_image->getHeight())
+ ));
+
+ upload_new_resource(assetUploadInfo);
+ }
+ }
+ else
+ {
+ LLNewFileResourceUploadInfo* info_p = new LLNewFileResourceUploadInfo(
+ filename,
+ asset_name,
+ asset_name, 0,
+ LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
+ LLFloaterPerms::getNextOwnerPerms("Uploads"),
+ LLFloaterPerms::getGroupPerms("Uploads"),
+ LLFloaterPerms::getEveryonePerms("Uploads"),
+ expected_upload_cost);
+ LLResourceUploadInfo::ptr_t uploadInfo(info_p);
+
+ upload_new_resource(uploadInfo);
+ }
}
}
@@ -653,8 +739,31 @@ bool get_bulk_upload_expected_cost(
LLPointer<LLImageFormatted> image_frmted = LLImageFormatted::createFromType(codec);
if (gDirUtilp->fileExists(filename) && image_frmted && image_frmted->load(filename))
{
- S32 biased_width = LLImageRaw::biasedDimToPowerOfTwo(image_frmted->getWidth(), LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
- S32 biased_height = LLImageRaw::biasedDimToPowerOfTwo(image_frmted->getHeight(), LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
+ S32 biased_width, biased_height;
+
+ S32 max_width = allow_2k ? gSavedSettings.getS32("max_texture_dimension_X") : 1024;
+ S32 max_height = allow_2k ? gSavedSettings.getS32("max_texture_dimension_Y") : 1024;
+
+ S32 orig_width = image_frmted->getWidth();
+ S32 orig_height = image_frmted->getHeight();
+
+ if (orig_width > max_width || orig_height > max_height)
+ {
+ // Calculate scale factors
+ F32 width_scale = (F32)max_width / (F32)orig_width;
+ F32 height_scale = (F32)max_height / (F32)orig_height;
+ F32 scale = llmin(width_scale, height_scale);
+
+ // Calculate new dimensions, preserving aspect ratio
+ biased_width = LLImageRaw::contractDimToPowerOfTwo(llclamp((S32)llroundf(orig_width * scale), 4, max_width));
+ biased_height = LLImageRaw::contractDimToPowerOfTwo(llclamp((S32)llroundf(orig_height * scale), 4, max_height));
+ }
+ else
+ {
+ biased_width = LLImageRaw::biasedDimToPowerOfTwo(orig_width, LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
+ biased_height = LLImageRaw::biasedDimToPowerOfTwo(orig_height, LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT);
+ }
+
total_cost += LLAgentBenefitsMgr::current().getTextureUploadCost(biased_width, biased_height);
S32 area = biased_width * biased_height;
if (area >= LLAgentBenefits::MIN_2K_TEXTURE_AREA)
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 86bd11d1eb..0cd4a739ee 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -3214,6 +3214,7 @@ void send_agent_update(bool force_send, bool send_reliable)
static F64 last_send_time = 0.0;
static U32 last_control_flags = 0;
+ static bool control_flags_follow_up = false;
static U8 last_render_state = 0;
static U8 last_flags = AU_FLAGS_NONE;
static LLQuaternion last_body_rot,
@@ -3291,6 +3292,20 @@ void send_agent_update(bool force_send, bool send_reliable)
break;
}
+ // example:
+ // user taps crouch (control_flags 4128), viewer sends 4128 then immediately 0
+ // server starts crouching motion but does not stop it, only once viewer sends 0
+ // second time will server stop the motion. follow_up exists to make sure all
+ // states like 'crouch' motion are properly cleared server side.
+ //
+ // P.S. Server probably shouldn't require a reminder to stop a motion,
+ // but at the moment it does.
+ if (control_flags_follow_up)
+ {
+ send_update = true;
+ break;
+ }
+
// check translation
constexpr F32 TRANSLATE_THRESHOLD = 0.01f;
if ((last_camera_pos_agent - camera_pos_agent).magVec() > TRANSLATE_THRESHOLD)
@@ -3424,6 +3439,7 @@ void send_agent_update(bool force_send, bool send_reliable)
// remember last update data
last_send_time = now;
+ control_flags_follow_up = last_control_flags != control_flags;
last_control_flags = control_flags;
last_render_state = render_state;
last_flags = flags;
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 80ede12b8a..e317ba262a 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -679,6 +679,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mVisuallyMuteSetting(AV_RENDER_NORMALLY),
mMutedAVColor(LLColor4::white /* used for "uninitialize" */),
mFirstFullyVisible(true),
+ mWaitingForMeshes(false),
mFirstDecloudTime(-1.f),
mFullyLoaded(false),
mPreviousFullyLoaded(false),
@@ -934,12 +935,12 @@ bool LLVOAvatar::isFullyTextured() const
bool LLVOAvatar::hasGray() const
{
- return !getIsCloud() && !isFullyTextured();
+ return !getHasMissingParts() && !isFullyTextured();
}
S32 LLVOAvatar::getRezzedStatus() const
{
- if (getIsCloud()) return 0;
+ if (getHasMissingParts()) return 0;
bool textured = isFullyTextured();
bool all_baked_loaded = allBakedTexturesCompletelyDownloaded();
if (textured && all_baked_loaded && getAttachmentCount() == mSimAttachments.size()) return 4;
@@ -986,30 +987,45 @@ bool LLVOAvatar::areAllNearbyInstancesBaked(S32& grey_avatars)
}
// static
-void LLVOAvatar::getNearbyRezzedStats(std::vector<S32>& counts, F32& avg_cloud_time, S32& cloud_avatars)
+void LLVOAvatar::getNearbyRezzedStats(std::vector<S32>& counts, F32& avg_cloud_time, S32& cloud_avatars, S32& pending_meshes, S32& control_avatars)
{
counts.clear();
counts.resize(5);
avg_cloud_time = 0;
cloud_avatars = 0;
+ pending_meshes = 0;
+ control_avatars = 0;
S32 count_avg = 0;
for (LLCharacter* character : LLCharacter::sInstances)
{
- if (LLVOAvatar* inst = (LLVOAvatar*)character)
+ LLVOAvatar* inst = (LLVOAvatar*)character;
+ if (inst && !inst->isUIAvatar() && !inst->isSelf())
{
- S32 rez_status = inst->getRezzedStatus();
- counts[rez_status]++;
- F32 time = inst->getFirstDecloudTime();
- if (time >= 0)
+ if (inst->isControlAvatar())
{
- avg_cloud_time+=time;
- count_avg++;
+ control_avatars++;
}
- if (!inst->isFullyLoaded() || time < 0)
+ else
{
- // still renders as cloud
- cloud_avatars++;
+ S32 rez_status = inst->getRezzedStatus();
+ counts[rez_status]++;
+ F32 time = inst->getFirstDecloudTime();
+ if (time >= 0)
+ {
+ avg_cloud_time += time;
+ count_avg++;
+ }
+ if (!inst->isFullyLoaded() || time < 0)
+ {
+ // still renders as cloud
+ cloud_avatars++;
+ if (rez_status >= 4
+ && inst->mWaitingForMeshes)
+ {
+ pending_meshes++;
+ }
+ }
}
}
}
@@ -1026,7 +1042,7 @@ std::string LLVOAvatar::rezStatusToString(S32 rez_status)
switch (rez_status)
{
case 0:
- return "cloud";
+ return "missing parts";
case 1:
return "gray";
case 2:
@@ -3505,7 +3521,7 @@ void LLVOAvatar::idleUpdateNameTagText(bool new_name)
is_muted = isInMuteList();
}
bool is_friend = isBuddy();
- bool is_cloud = getIsCloud();
+ bool is_cloud = getHasMissingParts();
if (is_appearance != mNameAppearance)
{
@@ -8255,7 +8271,7 @@ bool LLVOAvatar::isVisible() const
}
// Determine if we have enough avatar data to render
-bool LLVOAvatar::getIsCloud() const
+bool LLVOAvatar::getHasMissingParts() const
{
if (mIsDummy)
{
@@ -8462,8 +8478,12 @@ bool LLVOAvatar::updateIsFullyLoaded()
|| (mLoadedCallbackTextures < mCallbackTextureList.size() && mLastTexCallbackAddedTime.getElapsedTimeF32() < MAX_TEXTURE_WAIT_TIME_SEC)
|| !mPendingAttachment.empty()
|| (rez_status < 3 && !isFullyBaked())
- || hasPendingAttachedMeshes()
);
+ if (!loading)
+ {
+ mWaitingForMeshes = hasPendingAttachedMeshes();
+ loading = mWaitingForMeshes;
+ }
// compare amount of attachments to one reported by simulator
if (!isSelf() && mLastCloudAttachmentCount < mSimAttachments.size() && mSimAttachments.size() > 0)
@@ -11830,16 +11850,24 @@ void LLVOAvatar::readProfileQuery(S32 retries)
}
else
- { // wait until next frame
- LLUUID id = getID();
+ {
+ // wait until next frame
+ const LLUUID id = getID();
- LL::WorkQueue::getInstance("mainloop")->post([id, retries] {
- LLVOAvatar* avatar = (LLVOAvatar*) gObjectList.findObject(id);
- if(avatar)
+ LL::WorkQueue::getInstance("mainloop")->post([id, retries]
+ {
+ LLViewerObject* object = gObjectList.findObject(id);
+ if (object
+ && !object->isDead()
+ && object->isAvatar()) // probably excessive, pcode isn't supposed to change
{
- avatar->readProfileQuery(retries);
+ LLVOAvatar* avatar = (LLVOAvatar*)object;
+ if (avatar)
+ {
+ avatar->readProfileQuery(retries);
+ }
}
- });
+ });
}
}
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 8e5b95ef25..1e563c4869 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -401,7 +401,7 @@ public:
bool isTooComplex() const;
bool visualParamWeightsAreDefault();
- virtual bool getIsCloud() const;
+ virtual bool getHasMissingParts() const;
bool isFullyTextured() const;
bool hasGray() const;
S32 getRezzedStatus() const; // 0 = cloud, 1 = gray, 2 = textured, 3 = waiting for attachments, 4 = full.
@@ -427,6 +427,7 @@ protected:
private:
bool mFirstFullyVisible;
+ bool mWaitingForMeshes;
F32 mFirstDecloudTime;
LLFrameTimer mFirstAppearanceMessageTimer;
@@ -723,7 +724,7 @@ public:
bool isFullyBaked();
static bool areAllNearbyInstancesBaked(S32& grey_avatars);
- static void getNearbyRezzedStats(std::vector<S32>& counts, F32& avg_cloud_time, S32& cloud_avatars);
+ static void getNearbyRezzedStats(std::vector<S32>& counts, F32& avg_cloud_time, S32& cloud_avatars, S32& pending_meshes, S32& control_avatars);
static std::string rezStatusToString(S32 status);
//--------------------------------------------------------------------
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index ebba9ba291..653c7e82eb 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -1927,7 +1927,7 @@ void LLVOAvatarSelf::dumpTotalLocalTextureByteCount()
LL_INFOS() << "Total Avatar LocTex GL:" << (gl_bytes/1024) << "KB" << LL_ENDL;
}
-bool LLVOAvatarSelf::getIsCloud() const
+bool LLVOAvatarSelf::getHasMissingParts() const
{
// Let people know why they're clouded without spamming them into oblivion.
bool do_warn = false;
@@ -2237,14 +2237,18 @@ void LLVOAvatarSelf::appearanceChangeMetricsCoro(std::string url)
std::vector<S32> rez_counts;
F32 avg_time;
S32 total_cloud_avatars;
- LLVOAvatar::getNearbyRezzedStats(rez_counts, avg_time, total_cloud_avatars);
+ S32 waiting_for_meshes;
+ S32 control_avatars;
+ LLVOAvatar::getNearbyRezzedStats(rez_counts, avg_time, total_cloud_avatars, waiting_for_meshes, control_avatars);
for (S32 rez_stat = 0; rez_stat < rez_counts.size(); ++rez_stat)
{
std::string rez_status_name = LLVOAvatar::rezStatusToString(rez_stat);
msg["nearby"][rez_status_name] = rez_counts[rez_stat];
}
+ msg["nearby"]["waiting_for_meshes"] = waiting_for_meshes;
msg["nearby"]["avg_decloud_time"] = avg_time;
msg["nearby"]["cloud_total"] = total_cloud_avatars;
+ msg["nearby"]["animeshes"] = control_avatars;
// std::vector<std::string> bucket_fields("timer_name","is_self","grid_x","grid_y","is_using_server_bake");
std::vector<std::string> by_fields;
@@ -2826,6 +2830,12 @@ void LLVOAvatarSelf::setHoverOffset(const LLVector3& hover_offset, bool send_upd
//------------------------------------------------------------------------
bool LLVOAvatarSelf::needsRenderBeam()
{
+ static LLCachedControl<bool> enable_selection_hints(gSavedSettings, "EnableSelectionHints", true);
+ if (!enable_selection_hints)
+ {
+ return false;
+ }
+
LLTool *tool = LLToolMgr::getInstance()->getCurrentTool();
bool is_touching_or_grabbing = (tool == LLToolGrab::getInstance() && LLToolGrab::getInstance()->isEditing());
diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h
index f7cd974ab0..45985b2a80 100644
--- a/indra/newview/llvoavatarself.h
+++ b/indra/newview/llvoavatarself.h
@@ -129,7 +129,7 @@ public:
// Loading state
//--------------------------------------------------------------------
public:
- /*virtual*/ bool getIsCloud() const;
+ /*virtual*/ bool getHasMissingParts() const;
//--------------------------------------------------------------------
// Region state
diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp
index facda1d876..e9c765f9de 100644
--- a/indra/newview/llvoicewebrtc.cpp
+++ b/indra/newview/llvoicewebrtc.cpp
@@ -336,35 +336,37 @@ void LLWebRTCVoiceClient::updateSettings()
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE;
setVoiceEnabled(LLVoiceClient::getInstance()->voiceEnabled());
- static LLCachedControl<S32> sVoiceEarLocation(gSavedSettings, "VoiceEarLocation");
- setEarLocation(sVoiceEarLocation);
-
- static LLCachedControl<std::string> sInputDevice(gSavedSettings, "VoiceInputAudioDevice");
- setCaptureDevice(sInputDevice);
+ if (mVoiceEnabled)
+ {
+ static LLCachedControl<S32> sVoiceEarLocation(gSavedSettings, "VoiceEarLocation");
+ setEarLocation(sVoiceEarLocation);
- static LLCachedControl<std::string> sOutputDevice(gSavedSettings, "VoiceOutputAudioDevice");
- setRenderDevice(sOutputDevice);
+ static LLCachedControl<std::string> sInputDevice(gSavedSettings, "VoiceInputAudioDevice");
+ setCaptureDevice(sInputDevice);
- LL_INFOS("Voice") << "Input device: " << std::quoted(sInputDevice()) << ", output device: " << std::quoted(sOutputDevice()) << LL_ENDL;
+ static LLCachedControl<std::string> sOutputDevice(gSavedSettings, "VoiceOutputAudioDevice");
+ setRenderDevice(sOutputDevice);
- static LLCachedControl<F32> sMicLevel(gSavedSettings, "AudioLevelMic");
- setMicGain(sMicLevel);
+ LL_INFOS("Voice") << "Input device: " << std::quoted(sInputDevice()) << ", output device: " << std::quoted(sOutputDevice()) << LL_ENDL;
- llwebrtc::LLWebRTCDeviceInterface::AudioConfig config;
+ static LLCachedControl<F32> sMicLevel(gSavedSettings, "AudioLevelMic");
+ setMicGain(sMicLevel);
- static LLCachedControl<bool> sEchoCancellation(gSavedSettings, "VoiceEchoCancellation", true);
- config.mEchoCancellation = sEchoCancellation;
+ llwebrtc::LLWebRTCDeviceInterface::AudioConfig config;
- static LLCachedControl<bool> sAGC(gSavedSettings, "VoiceAutomaticGainControl", true);
- config.mAGC = sAGC;
+ static LLCachedControl<bool> sEchoCancellation(gSavedSettings, "VoiceEchoCancellation", true);
+ config.mEchoCancellation = sEchoCancellation;
- static LLCachedControl<U32> sNoiseSuppressionLevel(gSavedSettings,
- "VoiceNoiseSuppressionLevel",
- llwebrtc::LLWebRTCDeviceInterface::AudioConfig::ENoiseSuppressionLevel::NOISE_SUPPRESSION_LEVEL_VERY_HIGH);
- config.mNoiseSuppressionLevel = (llwebrtc::LLWebRTCDeviceInterface::AudioConfig::ENoiseSuppressionLevel) (U32)sNoiseSuppressionLevel;
+ static LLCachedControl<bool> sAGC(gSavedSettings, "VoiceAutomaticGainControl", true);
+ config.mAGC = sAGC;
- mWebRTCDeviceInterface->setAudioConfig(config);
+ static LLCachedControl<U32> sNoiseSuppressionLevel(gSavedSettings,
+ "VoiceNoiseSuppressionLevel",
+ llwebrtc::LLWebRTCDeviceInterface::AudioConfig::ENoiseSuppressionLevel::NOISE_SUPPRESSION_LEVEL_VERY_HIGH);
+ config.mNoiseSuppressionLevel = (llwebrtc::LLWebRTCDeviceInterface::AudioConfig::ENoiseSuppressionLevel)(U32)sNoiseSuppressionLevel;
+ mWebRTCDeviceInterface->setAudioConfig(config);
+ }
}
// Observers
diff --git a/indra/newview/res/ll_icon_small.ico b/indra/newview/res/ll_icon_small.ico
new file mode 100644
index 0000000000..a3f6877935
--- /dev/null
+++ b/indra/newview/res/ll_icon_small.ico
Binary files differ
diff --git a/indra/newview/res/resource.h b/indra/newview/res/resource.h
index e904f4a1a8..1d3289d784 100644
--- a/indra/newview/res/resource.h
+++ b/indra/newview/res/resource.h
@@ -30,6 +30,7 @@
#define IDREMOVE 3
#define IDI_LL_ICON 103
#define IDC_GRABHAND 104
+#define IDI_LL_ICON_SMALL 105
#define IDC_CURSOR1 134
#define IDC_CURSOR2 136
#define IDC_CURSOR3 147
diff --git a/indra/newview/res/viewerRes.rc b/indra/newview/res/viewerRes.rc
index b01f5e700d..08e381ebc5 100755
--- a/indra/newview/res/viewerRes.rc
+++ b/indra/newview/res/viewerRes.rc
@@ -56,6 +56,7 @@ END
// remains consistent on all systems.
IDI_LL_ICON ICON "ll_icon.ico"
IDI_LCD_LL_ICON ICON "icon1.ico"
+IDI_LL_ICON_SMALL ICON "ll_icon_small.ico"
/////////////////////////////////////////////////////////////////////////////
//
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index 94c8119d4d..654810e210 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -659,7 +659,6 @@ with the same filename but different name
<texture name="login_mp_logo" file_name="windows/login_mp_logo.png" preload="true" />
<texture name="login_mp_logo_small" file_name="windows/login_mp_logo_small.png" preload="true" />
- <texture name="first_login_image" file_name="windows/first_login_image.jpg" preload="true" />
<texture name="Stepper_Down_Off" file_name="widgets/Stepper_Down_Off.png" preload="false" />
<texture name="Stepper_Down_Press" file_name="widgets/Stepper_Down_Press.png" preload="false" />
diff --git a/indra/newview/skins/default/textures/windows/first_login_image.jpg b/indra/newview/skins/default/textures/windows/first_login_image.jpg
deleted file mode 100644
index 58c417081a..0000000000
--- a/indra/newview/skins/default/textures/windows/first_login_image.jpg
+++ /dev/null
Binary files differ
diff --git a/indra/newview/skins/default/xui/de/panel_login_first.xml b/indra/newview/skins/default/xui/de/panel_login_first.xml
deleted file mode 100644
index 038001157e..0000000000
--- a/indra/newview/skins/default/xui/de/panel_login_first.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<panel name="panel_login">
- <panel.string name="forgot_password_url">
- http://secondlife.com/account/request.php?lang=de
- </panel.string>
- <panel.string name="sign_up_url">
- https://join.secondlife.com/
- </panel.string>
- <layout_stack name="logo_stack">
- <layout_panel name="parent_panel2">
- <layout_stack name="widget_stack">
- <layout_panel name="widget_container">
- <combo_box label="Benutzername" name="username_combo" tool_tip="Bei der Registrierung gewählter Benutzername wie „berndschmidt12“ oder „Liebe Sonne“"/>
- <line_editor label="Kennwort" name="password_edit"/>
- <button label="Anmelden" name="connect_btn"/>
- <check_box label="Details speichern" name="remember_check"/>
- <text name="forgot_password_text">
- Kennwort vergessen
- </text>
- <text name="sign_up_text">
- Registrieren
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- <layout_panel name="parent_panel3">
- <layout_stack name="images_stack">
- <layout_panel name="images_container">
- <text name="image_caption_left">
- Ihr erster Schritt ist Learning Island. Suchen Sie die Pforte!
- </text>
- <text name="image_caption_right">
- Erkunden Sie dann Social Island und lernen Sie andere Einwohner kennen!
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- </layout_stack>
-</panel>
diff --git a/indra/newview/skins/default/xui/en/floater_test_slapp.xml b/indra/newview/skins/default/xui/en/floater_test_slapp.xml
index dd2720816a..5a13a0147e 100644
--- a/indra/newview/skins/default/xui/en/floater_test_slapp.xml
+++ b/indra/newview/skins/default/xui/en/floater_test_slapp.xml
@@ -8,7 +8,7 @@
width="500">
<floater.string
name="remove_folder_slapp">
- secondlife://app/remove_folder/?folder_id=
+ secondlife:///app/remove_folder/?folder_id=
</floater.string>
<text
type="string"
@@ -42,7 +42,7 @@
width="450"
layout="topleft"
left="16">
- secondlife://app/wear_folder/?folder_name=Daisy
+ secondlife:///app/wear_folder/?folder_name=Daisy
</text>
<text
type="string"
@@ -63,7 +63,7 @@
width="450"
layout="topleft"
left="16">
- secondlife://app/add_folder/?folder_name=Cardboard%20Boxbot
+ secondlife:///app/add_folder/?folder_name=Cardboard%20Boxbot
</text>
<text
type="string"
@@ -73,7 +73,7 @@
height="16"
width="450"
layout="topleft">
- secondlife://app/add_folder/?folder_id=59219db2-c260-87d3-213d-bb3bc298a3d8
+ secondlife:///app/add_folder/?folder_id=59219db2-c260-87d3-213d-bb3bc298a3d8
</text>
<text
type="string"
@@ -118,6 +118,6 @@
name="remove_folder_txt"
layout="topleft"
left="16">
- secondlife://app/remove_folder/?folder_id=
+ secondlife:///app/remove_folder/?folder_id=
</text>
</floater>
diff --git a/indra/newview/skins/default/xui/en/menu_url_parcel.xml b/indra/newview/skins/default/xui/en/menu_url_parcel.xml
index e0f1fcf9c3..95752dab66 100644
--- a/indra/newview/skins/default/xui/en/menu_url_parcel.xml
+++ b/indra/newview/skins/default/xui/en/menu_url_parcel.xml
@@ -16,7 +16,7 @@
layout="topleft"
name="show_on_map">
<menu_item_call.on_click
- function="Url.ShowOnMap" />
+ function="Url.ShowParcelOnMap" />
</menu_item_call>
<menu_item_separator
layout="topleft" />
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index a318093d7c..10c9efffd1 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -12674,4 +12674,15 @@ Select the "use as favorite folder" from a folder's menu to set it as the favori
Unable to apply material to the water exclusion surface.
<tag>fail</tag>
</notification>
+
+ <notification
+ icon="notify.tga"
+ name="ImageUploadResized"
+ type="alertmodal">
+ The texture you are uploading has been resized from [ORIGINAL_WIDTH]x[ORIGINAL_HEIGHT] to [NEW_WIDTH]x[NEW_HEIGHT] in order to to fit the maximum size of [MAX_WIDTH]x[MAX_HEIGHT] pixels.
+ <usetemplate
+ ignoretext="Image Upload Resized"
+ name="okignore"
+ yestext="OK"/>
+ </notification>
</notifications>
diff --git a/indra/newview/skins/default/xui/en/panel_login_first.xml b/indra/newview/skins/default/xui/en/panel_login_first.xml
deleted file mode 100644
index 0a8ae48b02..0000000000
--- a/indra/newview/skins/default/xui/en/panel_login_first.xml
+++ /dev/null
@@ -1,262 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<panel
- follows="all"
- height="768"
- layout="topleft"
- name="panel_login"
- focus_root="true"
- background_visible="true"
- bg_opaque_color="0.0 0.0 0.0 1"
- background_opaque="true"
- width="1024">
- <panel.string
- name="forgot_password_url">
- http://secondlife.com/account/request.php
- </panel.string>
- <panel.string
- name="sign_up_url">
- https://join.secondlife.com/
- </panel.string>
- <layout_stack
- follows="left|right|top|bottom"
- width="1024"
- height="768"
- left="0"
- name="logo_stack"
- orientation="vertical"
- top="0">
- <layout_panel
- height="18"
- auto_resize="false"
- name="page_top"
- width="1024" />
- <!-- start of logo stack -->
- <layout_panel
- height="130"
- min_height="10"
- auto_resize="false"
- name="parent_panel"
- width="1024">
- <layout_stack
- follows="left|right|top|bottom"
- height="100"
- left="0"
- name="logo_stack"
- orientation="horizontal"
- top="0"
- width="1024">
- <layout_panel
- height="110"
- min_height="10"
- auto_resize="true"
- name="logo_left"
- width="300" />
- <layout_panel
- auto_resize="false"
- follows="left|right|top"
- name="logo_container"
- width="225"
- left="0"
- top="0"
- height="105">
- <icon
- height="94"
- image_name="login_mp_logo"
- left="0"
- name="sl_logo"
- top="0" />
- </layout_panel>
- <layout_panel
- height="100"
- name="logo_right"
- auto_resize="true"
- width="300" />
- </layout_stack>
- </layout_panel>
- <!-- end of logo stack -->
- <!-- start of widget stack -->
- <layout_panel
- height="100"
- min_height="10"
- auto_resize="false"
- name="parent_panel2"
- width="1024">
- <layout_stack
- follows="left|right|top|bottom"
- height="80"
- left="0"
- name="widget_stack"
- orientation="horizontal"
- top="0"
- width="1024">
- <layout_panel
- height="80"
- min_height="10"
- auto_resize="true"
- name="widget_left"
- width="200" />
- <layout_panel
- auto_resize="false"
- follows="left|right|top"
- name="widget_container"
- width="730"
- left="0"
- top="0"
- height="80">
- <combo_box
- allow_text_entry="true"
- follows="left|bottom"
- height="32"
- left="42"
- label="Username"
- combo_editor.font="SansSerifLarge"
- max_chars="128"
- top="0"
- combo_editor.prevalidator="ascii"
- tool_tip="The username you chose when you registered, like bobsmith12 or Steller Sunshine"
- name="username_combo"
- width="232">
- <combo_box.combo_editor
- text_pad_left="8" />
- <combo_box.combo_button
- visible ="false"/>
- <combo_box.drop_down_button
- visible ="false"/>
- </combo_box>
- <line_editor
- follows="left|top"
- width="200"
- height="32"
- left="262"
- max_length_chars="16"
- name="password_edit"
- label="Password"
- text_pad_left="8"
- font="SansSerifLarge"
- is_password="true"
- select_on_focus="true"
- commit_on_focus_lost="false"
- top="0" />
- <button
- follows="left|top"
- image_unselected="PushButton_Login"
- image_pressed="PushButton_Login_Pressed"
- image_hover_unselected="PushButton_Login_Over"
- label="Log In"
- label_color="White"
- font="SansSerifLarge"
- name="connect_btn"
- left_pad="15"
- width="120"
- height="32"
- top="0" />
- <text
- follows="left|top"
- font="SansSerifLarge"
- font.style="BOLD"
- text_color="EmphasisColor"
- height="34"
- name="sign_up_text"
- left_pad="10"
- top="0"
- width="200"
- valign="center">
- Sign up
- </text>
- <check_box
- follows="left|top"
- font="SansSerifLarge"
- left="42"
- top="32"
- height="24"
- label="Remember me"
- word_wrap="down"
- check_button.bottom="3"
- name="remember_name"
- tool_tip="Already remembered user can be forgotten from Me &gt; Preferences &gt; Advanced &gt; Remembered Usernames."
- width="198" />
- <check_box
- control_name="RememberPassword"
- follows="left|top"
- font="SansSerifLarge"
- height="24"
- left="262"
- bottom_delta="0"
- label="Remember password"
- word_wrap="down"
- check_button.bottom="3"
- name="remember_password"
- width="198" />
- <text
- follows="left|top"
- font="SansSerifLarge"
- text_color="EmphasisColor"
- height="16"
- name="forgot_password_text"
- left="492"
- top="34"
- width="200">
- Forgotten password
- </text>
- </layout_panel>
- <layout_panel
- height="100"
- name="widget_right"
- auto_resize="true"
- width="200" />
- </layout_stack>
- </layout_panel>
- <!-- end of widget stack -->
- <!-- start of images stack -->
- <layout_panel
- height="500"
- min_height="10"
- auto_resize="false"
- name="parent_panel3"
- width="1024">
- <layout_stack
- follows="left|right|top|bottom"
- height="500"
- left="0"
- name="images_stack"
- orientation="horizontal"
- top="0"
- width="1024">
- <layout_panel
- height="500"
- min_height="10"
- auto_resize="true"
- name="images_left"
- width="96" />
- <layout_panel
- auto_resize="false"
- follows="left|right|top"
- name="images_container"
- width="675"
- left="0"
- top="0"
- height="500">
- <icon
- height="450"
- width="675"
- image_name="first_login_image"
- left="0"
- name="image_left"
- top="0" />
- </layout_panel>
- <layout_panel
- height="100"
- name="images_right"
- auto_resize="true"
- width="96" />
- </layout_stack>
- </layout_panel>
- <!-- end of images stack -->
- <layout_panel
- height="400"
- min_height="10"
- auto_resize="true"
- name="page_bottom"
- width="1024" />
- </layout_stack>
-</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
index c38af9d4fa..54105a7d4e 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
@@ -32,15 +32,15 @@
height="23"
increment="64"
initial_value="1024"
- label="Cache size (256 - 9984MB)"
+ label="Cache size (896 - 32768MB)"
label_width="150"
layout="topleft"
left="80"
- max_val="9984"
- min_val="256"
+ max_val="32768"
+ min_val="896"
top_pad="10"
name="cachesizespinner"
- width="200" />
+ width="210" />
<text
type="string"
length="1"
@@ -59,7 +59,7 @@
label="Clear Cache"
label_selected="Clear Cache"
layout="topleft"
- left_pad="30"
+ left_pad="20"
name="clear_cache"
top_delta="0"
width="100">
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 809c001904..8ab7b48d19 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml
@@ -90,7 +90,7 @@
name="online_visibility"
top_pad="15"
width="350" />
-
+
<check_box
enabled_control="EnableVoiceChat"
control_name="AutoDisengageMic"
@@ -101,6 +101,37 @@
name="auto_disengage_mic_check"
top_pad="10"
width="350" />
+ <check_box
+ control_name="EnableLookAtTarget"
+ height="16"
+ label="Enable LookAt"
+ tool_tip="Enable tracking cursor position with avatar head's rotation"
+ layout="topleft"
+ left="30"
+ name="enable_lookat_target"
+ top_pad="10"
+ width="350" />
+ <check_box
+ enabled_control="EnableLookAtTarget"
+ control_name="LimitLookAtTarget"
+ height="16"
+ label="Limit LookAt Distance"
+ tool_tip="Limit the look at target's distance by restricting it around the avatar's head"
+ layout="topleft"
+ left="50"
+ name="limit_lookat_distance"
+ top_pad="10"
+ width="350" />
+ <check_box
+ control_name="EnableSelectionHints"
+ height="16"
+ label="Enable Selection Hints"
+ tool_tip="Enable reporting and tracking current selection using 'beam' particles and character animations"
+ layout="topleft"
+ left="30"
+ name="enable_selection_hints"
+ top_pad="10"
+ width="350" />
<button
follows="left|top"
height="23"
diff --git a/indra/newview/skins/default/xui/en/panel_status_bar.xml b/indra/newview/skins/default/xui/en/panel_status_bar.xml
index 5e05eb2837..e53a25ff6b 100644
--- a/indra/newview/skins/default/xui/en/panel_status_bar.xml
+++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml
@@ -86,7 +86,7 @@
height="18"
left="0"
name="balance"
- tool_tip="Click to refresh your L$ balance"
+ tool_tip="L$ [AMT]&#10;Click to refresh your L$ balance.&#10;Double-click to display or hide your L$ balance."
v_pad="4"
top="0"
wrap="false"
diff --git a/indra/newview/skins/default/xui/es/panel_login_first.xml b/indra/newview/skins/default/xui/es/panel_login_first.xml
deleted file mode 100644
index ccb6858351..0000000000
--- a/indra/newview/skins/default/xui/es/panel_login_first.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<panel name="panel_login">
- <panel.string name="forgot_password_url">
- http://secondlife.com/account/request.php?lang=es
- </panel.string>
- <panel.string name="sign_up_url">
- https://join.secondlife.com/
- </panel.string>
- <layout_stack name="logo_stack">
- <layout_panel name="parent_panel2">
- <layout_stack name="widget_stack">
- <layout_panel name="widget_container">
- <combo_box label="Nombre de usuario" name="username_combo" tool_tip="El nombre de usuario que elegiste al registrarte, como bobsmith12 o Steller Sunshine"/>
- <line_editor label="Contraseña" name="password_edit"/>
- <button label="Iniciar sesión" name="connect_btn"/>
- <check_box label="Recordarme" name="remember_check"/>
- <text name="forgot_password_text">
- Contraseña olvidada
- </text>
- <text name="sign_up_text">
- Regístrate
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- <layout_panel name="parent_panel3">
- <layout_stack name="images_stack">
- <layout_panel name="images_container">
- <text name="image_caption_left">
- Tu primer destino es la Isla de aprendizaje. ¡Encuentra el portal de salida!
- </text>
- <text name="image_caption_right">
- A continuación, puedes explorar la Isla social y hablar con otros residentes nuevos.
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- </layout_stack>
-</panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_login_first.xml b/indra/newview/skins/default/xui/fr/panel_login_first.xml
deleted file mode 100644
index 8f40d0230c..0000000000
--- a/indra/newview/skins/default/xui/fr/panel_login_first.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<panel name="panel_login">
- <panel.string name="forgot_password_url">
- http://secondlife.com/account/request.php?lang=fr
- </panel.string>
- <panel.string name="sign_up_url">
- https://join.secondlife.com/
- </panel.string>
- <layout_stack name="logo_stack">
- <layout_panel name="parent_panel2">
- <layout_stack name="widget_stack">
- <layout_panel name="widget_container">
- <combo_box label="Nom d&apos;utilisateur" name="username_combo" tool_tip="Nom d&apos;utilisateur que vous avez choisi lors de votre inscription (par exemple, bobsmith12 ou Steller Sunshine)."/>
- <line_editor label="Mot de passe" name="password_edit"/>
- <button label="Connexion" name="connect_btn"/>
- <check_box font="SansSerifSmall" label="Mémoriser mes informations" name="remember_check"/>
- <text name="forgot_password_text">
- Mot de passe oublié
- </text>
- <text name="sign_up_text">
- S&apos;inscrire
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- <layout_panel name="parent_panel3">
- <layout_stack name="images_stack">
- <layout_panel name="images_container">
- <text name="image_caption_left">
- Votre première étape est Learning Island. Trouvez le portail de sortie.
- </text>
- <text name="image_caption_right">
- Puis explorez Social Island et faites la connaissance d&apos;autres résidents.
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- </layout_stack>
-</panel>
diff --git a/indra/newview/skins/default/xui/it/panel_login_first.xml b/indra/newview/skins/default/xui/it/panel_login_first.xml
deleted file mode 100644
index 5b04fd411a..0000000000
--- a/indra/newview/skins/default/xui/it/panel_login_first.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<panel name="panel_login">
- <panel.string name="forgot_password_url">
- http://secondlife.com/account/request.php?lang=it
- </panel.string>
- <panel.string name="sign_up_url">
- http://join.secondlife.com/
- </panel.string>
- <layout_stack name="logo_stack">
- <layout_panel name="parent_panel2">
- <layout_stack name="widget_stack">
- <layout_panel name="widget_container">
- <combo_box label="Nome utente" name="username_combo" tool_tip="Il nome utente che hai scelto durante la registrazione, come roby12 o Stella Solare"/>
- <line_editor label="Password" name="password_edit"/>
- <button label="Accedi" name="connect_btn"/>
- <check_box label="Ricordami" name="remember_check"/>
- <text name="forgot_password_text">
- Password dimenticata
- </text>
- <text name="sign_up_text">
- Registrati
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- <layout_panel name="parent_panel3">
- <layout_stack name="images_stack">
- <layout_panel name="images_container">
- <text name="image_caption_left">
- Il primo passo è a Learning Island. Trova il portale di uscita!
- </text>
- <text name="image_caption_right">
- Quindi esplora Social Island e incontra altri nuovi residenti.
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- </layout_stack>
-</panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_login_first.xml b/indra/newview/skins/default/xui/ja/panel_login_first.xml
deleted file mode 100644
index 0f987fc816..0000000000
--- a/indra/newview/skins/default/xui/ja/panel_login_first.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<panel name="panel_login">
- <panel.string name="forgot_password_url">
- https://secondlife.com/my/account/request.php?lang=ja-JP
- </panel.string>
- <panel.string name="sign_up_url">
- https://join.secondlife.com/?lang=ja
- </panel.string>
- <layout_stack name="logo_stack">
- <layout_panel name="page_top"/>
- <layout_panel name="parent_panel">
- <layout_stack name="logo_stack">
- <layout_panel name="logo_left"/>
- <layout_panel name="logo_container">
- <icon name="sl_logo"/>
- </layout_panel>
- <layout_panel auto_resize="true"/>
- </layout_stack>
- </layout_panel>
- <layout_panel name="parent_panel2">
- <layout_stack name="widget_stack">
- <layout_panel name="widget_left"/>
- <layout_panel name="widget_container">
- <combo_box label="ユーザ名" tool_tip="登録時に自分で選んだユーザー名(例:bobsmith12、Steller Sunshineなど)" name="username_combo">
- <combo_box.combo_editor/>
- <combo_box.combo_button/>
- <combo_box.drop_down_button/>
- </combo_box>
- <line_editor name="password_edit" label="パスワード"/>
- <button label="ログイン" name="connect_btn"/>
- <text name="sign_up_text" valign="center">
- サインアップ
- </text>
- <check_box label="ユーザ名を記憶" name="remember_name" tool_tip="すでに記憶されているユーザーは、「私」>「初期設定」>「詳細設定」>「記憶されたユーザー名」から削除できます。"/>
- <check_box label="パスワード記憶" name="remember_password"/>
- <text name="forgot_password_text">
- パスワードを忘れましたか?
- </text>
- </layout_panel>
- <layout_panel name="widget_right"/>
- </layout_stack>
- </layout_panel>
- <layout_panel name="parent_panel3">
- <layout_stack name="images_stack">
- <layout_panel name="images_left"/>
- <layout_panel name="images_container">
- <icon name="image_left"/>
- </layout_panel>
- <layout_panel name="images_right"/>
- </layout_stack>
- </layout_panel>
- <layout_panel name="page_bottom"/>
- </layout_stack>
-</panel>
diff --git a/indra/newview/skins/default/xui/pl/panel_login_first.xml b/indra/newview/skins/default/xui/pl/panel_login_first.xml
deleted file mode 100644
index 0604ecbcff..0000000000
--- a/indra/newview/skins/default/xui/pl/panel_login_first.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<panel name="panel_login">
- <layout_stack name="logo_stack">
- <layout_panel name="parent_panel2">
- <layout_stack name="widget_stack">
- <layout_panel name="widget_container">
- <combo_box label="Użytkownik" tool_tip="Nazwa użytkownika wybrana przy rejestracji, np. bobsmith12 lub Steller Sunshine" name="username_combo" />
- <line_editor name="password_edit" label="Hasło" />
- <button label="Zaloguj" name="connect_btn" />
- <check_box label="Zapamiętaj mnie" name="remember_check" />
- <text name="forgot_password_text">
- Zapomniałem/am hasła
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- <layout_panel name="parent_panel3">
- <layout_stack name="images_stack">
- <layout_panel name="images_container">
- <text name="image_caption_left">
- Wyspa Nauki to Twój pierwszy krok. Znajdź portal z wyjściem!
- </text>
- <text name="image_caption_right">
- Potem zwiedź Wyspę Towarzyską i poznaj innych nowych rezydentów!
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- </layout_stack>
-</panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_login_first.xml b/indra/newview/skins/default/xui/pt/panel_login_first.xml
deleted file mode 100644
index 86c61163bc..0000000000
--- a/indra/newview/skins/default/xui/pt/panel_login_first.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<panel name="panel_login">
- <panel.string name="forgot_password_url">
- http://secondlife.com/account/request.php?lang=pt
- </panel.string>
- <panel.string name="sign_up_url">
- https://join.secondlife.com/
- </panel.string>
- <layout_stack name="logo_stack">
- <layout_panel name="parent_panel2">
- <layout_stack name="widget_stack">
- <layout_panel name="widget_container">
- <combo_box label="Nome de usuário" name="username_combo" tool_tip="O nome de usuário que você escolheu ao fazer seu cadastro, como zecazc12 ou Magia Solar"/>
- <line_editor label="Senha" name="password_edit"/>
- <button label="Login" name="connect_btn"/>
- <check_box label="Lembrar-me" name="remember_check"/>
- <text name="forgot_password_text">
- Senha esquecida
- </text>
- <text name="sign_up_text">
- Cadastre-se
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- <layout_panel name="parent_panel3">
- <layout_stack name="images_stack">
- <layout_panel name="images_container">
- <text name="image_caption_left">
- Sua primeira parada é a Ilha da Educação. Encontre o portal de saída!
- </text>
- <text name="image_caption_right">
- Em seguida, explore a Ilha Social e encontre novos residentes!
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- </layout_stack>
-</panel>
diff --git a/indra/newview/skins/default/xui/ru/panel_login_first.xml b/indra/newview/skins/default/xui/ru/panel_login_first.xml
deleted file mode 100644
index 5db81ea7ca..0000000000
--- a/indra/newview/skins/default/xui/ru/panel_login_first.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<panel name="panel_login">
- <panel.string name="forgot_password_url">
- http://secondlife.com/account/request.php
- </panel.string>
- <panel.string name="sign_up_url">
- https://join.secondlife.com/
- </panel.string>
- <layout_stack name="logo_stack">
- <layout_panel name="parent_panel2">
- <layout_stack name="widget_stack">
- <layout_panel name="widget_container">
- <combo_box label="Имя пользователя" name="username_combo" tool_tip="Имя пользователя, которое вы выбрали при регистрации, например, «bobsmith12» или «Steller Sunshine»"/>
- <line_editor label="Пароль" name="password_edit"/>
- <button label="Войти" name="connect_btn"/>
- <check_box label="Запомнить меня" name="remember_check"/>
- <text name="forgot_password_text">
- Забытый пароль
- </text>
- <text name="sign_up_text">
- Регистрация
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- <layout_panel name="parent_panel3">
- <layout_stack name="images_stack">
- <layout_panel name="images_container">
- <text name="image_caption_left">
- Ваш первый шаг – Учебный остров. Найдите портал выхода!
- </text>
- <text name="image_caption_right">
- Затем исследуйте Социальный остров и познакомьтесь с другими новичками!
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- </layout_stack>
-</panel>
diff --git a/indra/newview/skins/default/xui/tr/panel_login_first.xml b/indra/newview/skins/default/xui/tr/panel_login_first.xml
deleted file mode 100644
index 1fc80c2b97..0000000000
--- a/indra/newview/skins/default/xui/tr/panel_login_first.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<panel name="panel_login">
- <panel.string name="forgot_password_url">
- http://secondlife.com/account/request.php
- </panel.string>
- <panel.string name="sign_up_url">
- https://join.secondlife.com/
- </panel.string>
- <layout_stack name="logo_stack">
- <layout_panel name="parent_panel2">
- <layout_stack name="widget_stack">
- <layout_panel name="widget_container">
- <combo_box label="Kullanıcı Adı" name="username_combo" tool_tip="Kaydolduğunuzda seçtiğiniz kullanıcı adı, örn. mustafayalcin12 veya Faruk Gungoren"/>
- <line_editor label="Parola" name="password_edit"/>
- <button label="Oturum Aç" name="connect_btn"/>
- <check_box label="Beni hatırla" name="remember_check"/>
- <text name="forgot_password_text">
- Parolamı unuttum
- </text>
- <text name="sign_up_text">
- Kaydol
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- <layout_panel name="parent_panel3">
- <layout_stack name="images_stack">
- <layout_panel name="images_container">
- <text name="image_caption_left">
- Başlangıç yeriniz Eğitim Adası. Haydi çıkış portalını bulun!
- </text>
- <text name="image_caption_right">
- Sonra da Sosyal Ada&apos;yı keşfe çıkın ve diğer LS sakinleriyle tanışın!
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- </layout_stack>
-</panel>
diff --git a/indra/newview/skins/default/xui/zh/panel_login_first.xml b/indra/newview/skins/default/xui/zh/panel_login_first.xml
deleted file mode 100644
index 4d72fcdd03..0000000000
--- a/indra/newview/skins/default/xui/zh/panel_login_first.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<panel name="panel_login">
- <panel.string name="forgot_password_url">
- http://secondlife.com/account/request.php
- </panel.string>
- <panel.string name="sign_up_url">
- http://join.secondlife.com/
- </panel.string>
- <layout_stack name="logo_stack">
- <layout_panel name="parent_panel2">
- <layout_stack name="widget_stack">
- <layout_panel name="widget_container">
- <combo_box label="使用者名稱" name="username_combo" tool_tip="使用者名稱是你註冊時所挑選的,例如 bobsmith12 或 Steller Sunshine"/>
- <line_editor label="密碼" name="password_edit"/>
- <button label="登入" name="connect_btn"/>
- <check_box label="記得我" name="remember_check"/>
- <text name="forgot_password_text">
- 忘記密碼
- </text>
- <text name="sign_up_text">
- 註冊
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- <layout_panel name="parent_panel3">
- <layout_stack name="images_stack">
- <layout_panel name="images_container">
- <text name="image_caption_left">
- 你在「學習島」的第一步。 找到離開的傳送門!
- </text>
- <text name="image_caption_right">
- 接著,到「社交島」探索,認識新的居民朋友!
- </text>
- </layout_panel>
- </layout_stack>
- </layout_panel>
- </layout_stack>
-</panel>
diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp
index d5e281bba8..10c68432a1 100644
--- a/indra/newview/tests/llviewerassetstats_test.cpp
+++ b/indra/newview/tests/llviewerassetstats_test.cpp
@@ -43,12 +43,15 @@ namespace LLStatViewer
LLTrace::SampleStatHandle<> FPS_SAMPLE("fpssample");
}
-void LLVOAvatar::getNearbyRezzedStats(std::vector<S32>& counts, F32& avg_cloud_time, S32& cloud_avatars)
+void LLVOAvatar::getNearbyRezzedStats(std::vector<S32>& counts, F32& avg_cloud_time, S32& cloud_avatars, S32& pending_meshes, S32& control_avatars)
{
counts.resize(3);
counts[0] = 0;
counts[1] = 0;
counts[2] = 1;
+ cloud_avatars = 0;
+ pending_meshes = 0;
+ control_avatars = 0;
}
// static
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index c778f1e838..ceb05980a5 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -151,7 +151,6 @@ class ViewerManifest(LLManifest):
with self.prefix(src_dst="skins"):
# include the entire textures directory recursively
with self.prefix(src_dst="*/textures"):
- self.path("*/*.jpg")
self.path("*/*.png")
self.path("*.tga")
self.path("*.j2c")
@@ -559,6 +558,9 @@ class Windows_x86_64_Manifest(ViewerManifest):
):
self.path(libfile)
+ if self.args['discord'] == 'ON':
+ self.path("discord_partner_sdk.dll")
+
if self.args['openal'] == 'ON':
# Get openal dll
self.path("OpenAL32.dll")
@@ -1021,6 +1023,13 @@ class Darwin_x86_64_Manifest(ViewerManifest):
):
self.path2basename(relpkgdir, libfile)
+ # Discord social SDK
+ if self.args['discord'] == 'ON':
+ for libfile in (
+ "libdiscord_partner_sdk.dylib",
+ ):
+ self.path2basename(relpkgdir, libfile)
+
# OpenAL dylibs
if self.args['openal'] == 'ON':
for libfile in (
@@ -1825,6 +1834,7 @@ if __name__ == "__main__":
extra_arguments = [
dict(name='bugsplat', description="""BugSplat database to which to post crashes,
if BugSplat crash reporting is desired""", default=''),
+ dict(name='discord', description="""Indication discord social sdk libraries are needed""", default='OFF'),
dict(name='openal', description="""Indication openal libraries are needed""", default='OFF'),
dict(name='tracy', description="""Indication tracy profiler is enabled""", default='OFF'),
]