diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 765fa76d5e..3c9a572374 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -265,7 +265,7 @@ jobs:
- name: Upload executable
if: steps.build.outputs.viewer_app
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v5
with:
name: "${{ steps.build.outputs.artifact }}-app"
path: |
@@ -275,13 +275,13 @@ jobs:
# artifact for that too.
- name: Upload symbol file
if: steps.build.outputs.symbolfile
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v5
with:
name: "${{ steps.build.outputs.artifact }}-symbols"
path: ${{ steps.build.outputs.symbolfile }}
- name: Upload metadata
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v5
with:
name: "${{ steps.build.outputs.artifact }}-metadata"
# emitted by build.sh, possibly multiple lines
@@ -289,7 +289,7 @@ jobs:
${{ steps.build.outputs.metadata }}
- name: Upload physics package
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v5
# should only be set for viewer-private
if: matrix.configuration == 'Release' && steps.build.outputs.physicstpv
with:
@@ -369,13 +369,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Download viewer exe
- uses: actions/download-artifact@v5
+ uses: actions/download-artifact@v6
with:
name: Windows-app
path: _artifacts
- name: Download Windows Symbols
if: env.BUGSPLAT_USER && env.BUGSPLAT_PASS
- uses: actions/download-artifact@v5
+ uses: actions/download-artifact@v6
with:
name: Windows-symbols
- name: Extract viewer pdb
@@ -405,7 +405,7 @@ jobs:
steps:
- name: Download Mac Symbols
if: env.BUGSPLAT_USER && env.BUGSPLAT_PASS
- uses: actions/download-artifact@v5
+ uses: actions/download-artifact@v6
with:
name: macOS-symbols
- name: Post Mac symbols
@@ -425,11 +425,11 @@ jobs:
runs-on: ubuntu-latest
if: needs.setup.outputs.release_run
steps:
- - uses: actions/download-artifact@v5
+ - uses: actions/download-artifact@v6
with:
pattern: "*-installer"
- - uses: actions/download-artifact@v5
+ - uses: actions/download-artifact@v6
with:
pattern: "*-metadata"
diff --git a/.github/workflows/build_viewer.yml b/.github/workflows/build_viewer.yml
index 4d74d5ba3d..1f86943641 100644
--- a/.github/workflows/build_viewer.yml
+++ b/.github/workflows/build_viewer.yml
@@ -482,7 +482,7 @@ jobs:
dumpSyms: false
- name: Publish artifacts
if: runner.os == 'Windows'
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v5
with:
name: ${{ env.FS_RELEASE_TYPE }}-${{ matrix.os }}-${{ matrix.variant }}-${{ matrix.grid }}-artifacts.zip
path: |
@@ -491,7 +491,7 @@ jobs:
- name: publish Linux artifacts
if: runner.os == 'Linux'
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v5
with:
name: ${{ env.FS_RELEASE_TYPE }}-${{ matrix.os }}-${{ matrix.variant }}-${{matrix.grid}}-artifacts.zip
path: |
@@ -500,7 +500,7 @@ jobs:
- name: publish MacOS artifacts
if: runner.os == 'macOS'
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v5
with:
name: ${{ env.FS_RELEASE_TYPE }}-${{ matrix.os }}-${{ matrix.variant }}-${{matrix.grid}}-artifacts.zip
path: |
@@ -529,7 +529,7 @@ jobs:
run: pip install discord-webhook
- name: Download artifacts
- uses: actions/download-artifact@v5
+ uses: actions/download-artifact@v6
id: download
with:
path: to_deploy
@@ -581,7 +581,7 @@ jobs:
# Upload Build Info Artifact (note that this file is expected to be identical for each matrix run, so items like OS and VARIANT cannot be in this file.)
- name: Upload Tag Info
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v5
with:
name: build_info
path: build_info.json
diff --git a/.github/workflows/sign.yml b/.github/workflows/sign.yml
index 828f8fd6ad..d49d51980f 100644
--- a/.github/workflows/sign.yml
+++ b/.github/workflows/sign.yml
@@ -62,7 +62,7 @@ jobs:
files_json=$(ls setup_exe_files | jq -R . | jq -s -c .)
echo "setup_files=$files_json" >> $GITHUB_OUTPUT
- name: Upload Setup.exe Files
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v5
with:
name: setup-exe-files
path: setup_exe_files/
@@ -86,7 +86,7 @@ jobs:
shell: bash
- name: Download Setup.exe Files Artifact
- uses: actions/download-artifact@v5
+ uses: actions/download-artifact@v6
with:
name: setup-exe-files
path: setup_exe_files
@@ -97,7 +97,7 @@ jobs:
shell: bash
# - name: Upload unsigned artifact
# id: upload-unsigned-artifact
- # uses: actions/upload-artifact@v4
+ # uses: actions/upload-artifact@v5
# with:
# name: unsigned-artifact-${{ matrix.file }}
# path: to_sign/${{ matrix.file }}
@@ -115,7 +115,7 @@ jobs:
# wait-for-completion: true
# output-artifact-directory: 'application-signed'
- name: Azure Trusted Signing
- uses: azure/trusted-signing-action@v0.5.9
+ uses: azure/trusted-signing-action@v0.5.10
with:
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
@@ -129,14 +129,14 @@ jobs:
files-folder-filter: exe
# - name: Upload signed artifact
- # uses: actions/upload-artifact@v4
+ # uses: actions/upload-artifact@v5
# with:
# name: signed-artifact-${{ matrix.file }}
# path: ./application-signed
# - name: Upload unsigned artifact
- name: Upload signed artifact
id: upload-unsigned-artifact
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@v5
with:
name: unsigned-artifact-${{ matrix.file }}
path: to_sign\${{ matrix.file }}
diff --git a/autobuild.xml b/autobuild.xml
index c00cf38d65..baebc62c3a 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -720,11 +720,11 @@
archive
name
darwin64
@@ -734,11 +734,11 @@
archive
name
linux64
@@ -748,11 +748,11 @@
archive
name
windows64
@@ -765,7 +765,7 @@
copyright
Copyright (c) 2017, Linden Research, Inc.
version
- 1.24.0.202510081737_139.0.40_g465474a_chromium-139.0.7258.139
+ 1.26.0.202510161627_139.0.40_g465474a_chromium-139.0.7258.139
name
dullahan
description
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index 4bdec91c28..5e92f59964 100644
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -197,6 +197,8 @@ if (LINUX)
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--no-keep-memory -Wl,--build-id -Wl,-rpath,'$ORIGIN:$ORIGIN/../lib' -Wl,--exclude-libs,ALL")
set(CMAKE_CXX_FLAGS_DEBUG "-fno-inline ${CMAKE_CXX_FLAGS_DEBUG}")
+ # Prefer static libraries on Linux
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ".so;.a")
endif (LINUX)
if (DARWIN)
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index 9f93fbc039..73e8d7184a 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -113,6 +113,9 @@ if(WINDOWS)
elseif (MSVC_VERSION GREATER_EQUAL 1930 AND MSVC_VERSION LESS 1950) # Visual Studio 2022
set(MSVC_VER 140)
set(MSVC_TOOLSET_VER 143)
+ elseif (MSVC_VERSION GREATER_EQUAL 1950 AND MSVC_VERSION LESS 1970) # Visual Studio 2026
+ set(MSVC_VER 140)
+ set(MSVC_TOOLSET_VER 145)
else (MSVC80)
MESSAGE(WARNING "New MSVC_VERSION ${MSVC_VERSION} of MSVC: adapt Copy3rdPartyLibs.cmake")
endif (MSVC80)
@@ -150,6 +153,7 @@ if(WINDOWS)
msvcp${MSVC_VER}_atomic_wait.dll
msvcp${MSVC_VER}_codecvt_ids.dll
#msvcr${MSVC_VER}.dll # Can't build with older VS versions anyway - no need trying to copy this file
+ vccorlib${MSVC_VER}.dll
vcruntime${MSVC_VER}.dll
vcruntime${MSVC_VER}_1.dll
vcruntime${MSVC_VER}_threads.dll
diff --git a/indra/cmake/GStreamer10Plugin.cmake b/indra/cmake/GStreamer10Plugin.cmake
index cb83d09d8a..875ebfc194 100644
--- a/indra/cmake/GStreamer10Plugin.cmake
+++ b/indra/cmake/GStreamer10Plugin.cmake
@@ -1,5 +1,6 @@
# -*- cmake -*-
include(Prebuilt)
+include(GLIB) # add glib includes
if (NOT LINUX)
return()
endif()
@@ -10,4 +11,12 @@ use_system_binary(gstreamer10)
use_prebuilt_binary(gstreamer10)
use_prebuilt_binary(libxml2)
-target_include_directories( ll::gstreamer SYSTEM INTERFACE ${LIBS_PREBUILT_DIR}/include/gstreamer-1.0)
+# make sure glib is found
+set(_gstreamer10_include_dirs
+ ${LIBS_PREBUILT_DIR}/include/gstreamer-1.0
+ ${GLIB_INCLUDE_DIRS}
+)
+list(REMOVE_ITEM _gstreamer10_include_dirs "")
+#
+
+target_include_directories( ll::gstreamer SYSTEM INTERFACE ${_gstreamer10_include_dirs})
diff --git a/indra/cmake/LLKDU.cmake b/indra/cmake/LLKDU.cmake
index 65268e8945..8a86284421 100644
--- a/indra/cmake/LLKDU.cmake
+++ b/indra/cmake/LLKDU.cmake
@@ -32,7 +32,7 @@ if (USE_KDU)
find_library(KDU_LIBRARY
NAMES
libkdu.a
- libkdu${ND_KDU_SUFFIX} // FS-specific naming
+ libkdu${ND_KDU_SUFFIX}.a // FS-specific naming
PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
endif (WINDOWS)
diff --git a/indra/cmake/LLPrimitive.cmake b/indra/cmake/LLPrimitive.cmake
index 2699f8efee..d3dc5f981c 100644
--- a/indra/cmake/LLPrimitive.cmake
+++ b/indra/cmake/LLPrimitive.cmake
@@ -56,3 +56,11 @@ find_library(COLLADADOM_LIBRARY
PATHS "${ARCH_PREBUILT_DIRS_RELEASE}" REQUIRED NO_DEFAULT_PATH)
target_link_libraries(ll::colladadom INTERFACE ${COLLADADOM_LIBRARY} ll::boost ll::libxml ll::minizip-ng)
+
+# GLIB uses pcre, so we need to keep it for Linux builds
+if (LINUX)
+ add_library( ll::pcre INTERFACE IMPORTED )
+ use_prebuilt_binary(pcre)
+ target_link_libraries( ll::pcre INTERFACE pcrecpp pcre )
+endif ()
+#
\ No newline at end of file
diff --git a/indra/llaudio/llaudioengine.h b/indra/llaudio/llaudioengine.h
index 2a2355b019..aa0617f936 100644
--- a/indra/llaudio/llaudioengine.h
+++ b/indra/llaudio/llaudioengine.h
@@ -39,6 +39,10 @@
#include "llframetimer.h"
#include "llassettype.h"
#include "llextendedstatus.h"
+// [FIRE-36022] - Removing my USB headset crashes entire viewer
+// Need to include for audio device mutex shared with other audio/voice systems.
+#include "inlinemutexs.h"
+// [FIRE-36022]
#include "lllistener.h"
diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp
index e9996b93e0..7daaea1c76 100644
--- a/indra/llaudio/llaudioengine_fmodstudio.cpp
+++ b/indra/llaudio/llaudioengine_fmodstudio.cpp
@@ -44,6 +44,9 @@
#include "sound_ids.h"
+// [FIRE-36022] - Removing my USB headset crashes entire viewer
+using namespace std::chrono_literals; // Needed for shared timed mutex to use time
+// [FIRE-36022]
constexpr U32 EXTRA_SOUND_CHANNELS = 10;
FMOD_RESULT F_CALL windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels);
@@ -113,8 +116,14 @@ static void set_device(FMOD::System* system, const LLUUID& device_uuid)
}
}
-FMOD_RESULT F_CALL systemCallback(FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACK_TYPE type, void *commanddata1, void *commanddata2, void* userdata)
+// [FIRE-36022] - Removing my USB headset crashes entire viewer
+// According to FMOD, not having this method static is very bad.
+//FMOD_RESULT F_CALL systemCallback(FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACK_TYPE type, void *commanddata1, void *commanddata2, void* userdata)
+static FMOD_RESULT F_CALL systemCallback(FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACK_TYPE type, void *commanddata1, void *commanddata2, void* userdata)
{
+ try // Try catch needed for uniquie lock as will throw an exception if a second lock is attempted or the mutex is invalid
+ {
+// [FIRE-36022]
FMOD::System* sys = (FMOD::System*)system;
LLAudioEngine_FMODSTUDIO* audio_engine = (LLAudioEngine_FMODSTUDIO*)userdata;
@@ -124,6 +133,17 @@ FMOD_RESULT F_CALL systemCallback(FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACK_TYPE
LL_DEBUGS("FMOD") << "FMOD system callback FMOD_SYSTEM_CALLBACK_DEVICELISTCHANGED" << LL_ENDL;
if (sys && audio_engine)
{
+ // [FIRE-36022] - Removing my USB headset crashes entire viewer
+ // Attempt to lock the access to the audio device, wait up to 1 second for other threads to unlock.
+ std::unique_lock lock(gAudioDeviceMutex, 1s);
+ // If the lock could not be accessed, return as we don't have hardware access and will need to try again another pass.
+ // Prevents threads from interacting with the hardware at the same time as other audio/voice threads.
+ if (!lock.owns_lock())
+ {
+ LL_INFOS() << "Could not access the audio device mutex, trying again later" << LL_ENDL;
+ return FMOD_OK; // Could be a FMOD_ERR_ALREADY_LOCKED;
+ }
+ // [FIRE-36022]
set_device(sys, audio_engine->getSelectedDeviceUUID());
audio_engine->OnOutputDeviceListChanged(audio_engine->getDevices());
}
@@ -132,6 +152,34 @@ FMOD_RESULT F_CALL systemCallback(FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACK_TYPE
break;
}
return FMOD_OK;
+ // [FIRE-36022] - Removing my USB headset crashes entire viewer
+ }
+ // There are two exceptions that unique_lock can trigger, operation_not_permitted or resource_deadlock_would_occur
+ catch (const std::system_error& e)
+ {
+ if (e.code() == std::errc::resource_deadlock_would_occur)
+ {
+ LL_WARNS() << "Exception FMOD: " << e.code() << " " << e.what() << LL_ENDL;
+ return FMOD_ERR_ALREADY_LOCKED;
+ }
+ else if (e.code() == std::errc::operation_not_permitted)
+ {
+ LL_WARNS() << "Exception FMOD: " << e.code() << " " << e.what() << LL_ENDL;
+ return FMOD_ERR_ALREADY_LOCKED;
+ }
+ else
+ {
+ LL_WARNS() << "Exception FMOD: " << e.code() << " " << e.what() << LL_ENDL;
+ }
+
+ return FMOD_ERR_ALREADY_LOCKED;
+ }
+ catch (const std::exception& e)
+ {
+ LL_WARNS() << "Exception FMOD: " << " " << e.what() << LL_ENDL;
+ return FMOD_ERR_ALREADY_LOCKED;
+ }
+ // [FIRE-36022]
}
LLAudioEngine_FMODSTUDIO::LLAudioEngine_FMODSTUDIO(bool enable_profiler, U32 resample_method)
@@ -311,6 +359,11 @@ bool LLAudioEngine_FMODSTUDIO::init(void* userdata, const std::string &app_title
LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() FMOD Studio initialized correctly" << LL_ENDL;
FMOD_ADVANCEDSETTINGS settings_dump = { };
+ // [FIRE-36022] - Removing my USB headset crashes entire viewer
+ // With the FMOD debug library used, turns out this object needs to have a size assigned to it otherwise it will fail.
+ // So the viewer never got any advanced settings for the info below.
+ settings_dump.cbSize = sizeof(FMOD_ADVANCEDSETTINGS);
+ // [FIRE-36022]
mSystem->getAdvancedSettings(&settings_dump);
LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): resampler=" << settings_dump.resamplerMethod << " bytes" << LL_ENDL;
@@ -373,7 +426,47 @@ LLAudioEngine_FMODSTUDIO::output_device_map_t LLAudioEngine_FMODSTUDIO::getDevic
void LLAudioEngine_FMODSTUDIO::setDevice(const LLUUID& device_uuid)
{
mSelectedDeviceUUID = device_uuid;
+ // [FIRE-36022] - Removing my USB headset crashes entire viewer
+ try // Try catch needed for uniquie lock as will throw an exception if a second lock is attempted or the mutex is invalid
+ {
+ // Attempt to lock the access to the audio device, wait up to 1 second for other threads to unlock.
+ std::unique_lock lock(gAudioDeviceMutex, 1s);
+ // If the lock could not be accessed, return as we don't have hardware access and will need to try again another pass.
+ // Prevents threads from interacting with the hardware at the same time as other audio/voice threads.
+ if (!lock.owns_lock())
+ {
+ LL_INFOS() << "Could not access the audio device mutex, trying again later" << LL_ENDL;
+ return;
+ }
+ // [FIRE-36022]
set_device(mSystem, device_uuid);
+ // [FIRE-36022] - Removing my USB headset crashes entire viewer
+ }
+ // There are two exceptions that unique_lock can trigger, operation_not_permitted or resource_deadlock_would_occur
+ catch (const std::system_error& e)
+ {
+ if (e.code() == std::errc::resource_deadlock_would_occur)
+ {
+ LL_WARNS() << "Exception FMOD: " << e.code() << " " << e.what() << LL_ENDL;
+ }
+ else if (e.code() == std::errc::operation_not_permitted)
+ {
+ LL_WARNS() << "Exception FMOD: " << e.code() << " " << e.what() << LL_ENDL;
+ }
+ else
+ {
+ LL_WARNS() << "Exception FMOD: " << e.code() << " " << e.what() << LL_ENDL;
+ }
+
+ return;
+ }
+ catch (const std::exception& e)
+ {
+ LL_WARNS() << "Exception FMOD: " << " " << e.what() << LL_ENDL;
+ return;
+ }
+ // [FIRE-36022]
+
}
std::string LLAudioEngine_FMODSTUDIO::getDriverName(bool verbose)
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 0d88dec885..1ba315b11a 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -122,6 +122,7 @@ set(llcommon_HEADER_FILES
fsyspath.h
function_types.h
indra_constants.h
+ inlinemutexs.h
lazyeventapi.h
linden_common.h
llalignedarray.h
diff --git a/indra/llcommon/inlinemutexs.h b/indra/llcommon/inlinemutexs.h
new file mode 100644
index 0000000000..3b8ab5c4ef
--- /dev/null
+++ b/indra/llcommon/inlinemutexs.h
@@ -0,0 +1,39 @@
+/**
+* @file inlinemutexs.h
+* @brief Declaration of inline mutexs
+* @author minerjr@firestorm
+*
+ * $LicenseInfo:firstyear=2025&license=fsviewerlgpl$
+ * Phoenix Firestorm Viewer Source Code
+ * Copyright (C) 2025, Minerjr
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA
+ * http://www.firestormviewer.org
+ * $/LicenseInfo$
+*/
+
+#ifndef INLINE_MUTEXS_HEADER
+#define INLINE_MUTEXS_HEADER
+#include
+#include
+#include
+
+// Audio device mutex to be shared between audio engine and Voice systems to
+// syncronize on when audio hardware accessed for disconnected/connecting hardware
+// Uses Timed Mutex so as to not lockup the threads forever.
+inline std::timed_mutex gAudioDeviceMutex;
+#endif
diff --git a/indra/llcommon/lltreeiterators.h b/indra/llcommon/lltreeiterators.h
index cef501b987..22b21af955 100644
--- a/indra/llcommon/lltreeiterators.h
+++ b/indra/llcommon/lltreeiterators.h
@@ -238,7 +238,22 @@ private:
mParents.pop_back();
}
/// equality
- bool equal(const self_type& that) const { return this->mParents == that.mParents; }
+ bool equal(const self_type& that) const
+ {
+ if (this == &that)
+ {
+ return true;
+ }
+
+ const bool empty = mParents.empty();
+ const bool that_empty = that.mParents.empty();
+ if (empty || that_empty)
+ {
+ return empty && that_empty;
+ }
+
+ return mParents == that.mParents;
+ }
/// implement dereference/indirection operators
ptr_type& dereference() const { return const_cast(mParents.back()); }
@@ -373,7 +388,22 @@ private:
mSkipChildren = false;
}
/// equality
- bool equal(const self_type& that) const { return this->mPending == that.mPending; }
+ bool equal(const self_type& that) const
+ {
+ if (this == &that)
+ {
+ return true;
+ }
+
+ const bool empty = mPending.empty();
+ const bool that_empty = that.mPending.empty();
+ if (empty || that_empty)
+ {
+ return empty && that_empty;
+ }
+
+ return mPending == that.mPending;
+ }
/// implement dereference/indirection operators
ptr_type& dereference() const { return const_cast(mPending.back()); }
@@ -474,7 +504,22 @@ private:
makeCurrent();
}
/// equality
- bool equal(const self_type& that) const { return this->mPending == that.mPending; }
+ bool equal(const self_type& that) const
+ {
+ if (this == &that)
+ {
+ return true;
+ }
+
+ const bool empty = mPending.empty();
+ const bool that_empty = that.mPending.empty();
+ if (empty || that_empty)
+ {
+ return empty && that_empty;
+ }
+
+ return mPending == that.mPending;
+ }
/// implement dereference/indirection operators
ptr_type& dereference() const { return const_cast(mPending.back().first); }
@@ -611,7 +656,22 @@ private:
mPending.push_back(*chi);
}
/// equality
- bool equal(const self_type& that) const { return this->mPending == that.mPending; }
+ bool equal(const self_type& that) const
+ {
+ if (this == &that)
+ {
+ return true;
+ }
+
+ const bool empty = mPending.empty();
+ const bool that_empty = that.mPending.empty();
+ if (empty || that_empty)
+ {
+ return empty && that_empty;
+ }
+
+ return mPending == that.mPending;
+ }
/// implement dereference/indirection operators
ptr_type& dereference() const { return const_cast(mPending.front()); }
diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp
index afcbafd249..9b8ce58cbd 100644
--- a/indra/llprimitive/lldaeloader.cpp
+++ b/indra/llprimitive/lldaeloader.cpp
@@ -1131,7 +1131,13 @@ bool LLDAELoader::OpenFile(const std::string& filename)
LLModel* mdl = *i;
if(mdl->getStatus() != LLModel::NO_ERRORS)
{
- setLoadState(ERROR_MODEL + mdl->getStatus()) ;
+ // Fix deprecated arithmetic between different enum types (ERROR_MODEL + EModelStatus)
+ // Ugly fix. could use a helper instead but its only called in two places.
+ // setLoadState(ERROR_MODEL + mdl->getStatus());
+ setLoadState(
+ static_cast(
+ static_cast(ERROR_MODEL) + static_cast(mdl->getStatus())));
+ //
return false; //abort
}
diff --git a/indra/llui/llaccordionctrl.cpp b/indra/llui/llaccordionctrl.cpp
index 1a64c2699d..2cd394476e 100644
--- a/indra/llui/llaccordionctrl.cpp
+++ b/indra/llui/llaccordionctrl.cpp
@@ -303,11 +303,8 @@ void LLAccordionCtrl::ctrlSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S3
return;
LLRect panel_rect = panel->getRect();
panel_rect.setLeftTopAndSize( left, top, width, height);
- if (panel->getRect() != panel_rect)
- {
- panel->reshape( width, height, 1);
- panel->setRect(panel_rect);
- }
+ panel->reshape( width, height, 1);
+ panel->setRect(panel_rect);
}
void LLAccordionCtrl::ctrlShiftVertical(LLView* panel, S32 delta)
diff --git a/indra/llwebrtc/llwebrtc.cpp b/indra/llwebrtc/llwebrtc.cpp
index 3bb0d3d947..31d1bbf839 100644
--- a/indra/llwebrtc/llwebrtc.cpp
+++ b/indra/llwebrtc/llwebrtc.cpp
@@ -27,6 +27,11 @@
#include "llwebrtc_impl.h"
#include
#include
+// [FIRE-36022] - Removing my USB headset crashes entire viewer
+// Needed for accessing the inline timed mutex for accessing audio hardware.
+#include
+#include
+// [FIRE-36022]
#include "api/audio_codecs/audio_decoder_factory.h"
#include "api/audio_codecs/audio_encoder_factory.h"
@@ -39,6 +44,14 @@
#include "modules/audio_mixer/audio_mixer_impl.h"
#include "api/environment/environment_factory.h"
+// [FIRE-36022] - Removing my USB headset crashes entire viewer
+// Audio device mutex to be shared between audio engine and Voice systems to
+// syncronize on when audio hardware accessed for disconnected/connecting hardware
+// Uses Timed Mutex so as to not lockup the threads forever.
+inline std::timed_mutex gAudioDeviceMutex;
+// Need to use to access the 3 second timeout for the lock.
+using namespace std::chrono_literals;
+// [FIRE-36022]
namespace llwebrtc
{
#if WEBRTC_WIN
@@ -269,7 +282,11 @@ void LLWebRTCImpl::init()
webrtc::InitializeSSL();
// Normal logging is rather spammy, so turn it off.
+ // [FIRE-36022] - Removing my USB headset crashes entire viewer
+ // Turn on more verbose logging as we are looking for crashes.
webrtc::LogMessage::LogToDebug(webrtc::LS_NONE);
+ //webrtc::LogMessage::LogToDebug(webrtc::LS_VERBOSE);
+ // [FIRE-36022]
webrtc::LogMessage::SetLogToStderr(true);
webrtc::LogMessage::AddLogToStream(mLogSink, webrtc::LS_VERBOSE);
@@ -463,8 +480,24 @@ void LLWebRTCImpl::unsetDevicesObserver(LLWebRTCDevicesObserver *observer)
// must be run in the worker thread.
void LLWebRTCImpl::workerDeployDevices()
{
+ // [FIRE-36022] - Removing my USB headset crashes entire viewer
+ try // Try catch needed for uniquie lock as will throw an exception if a second lock is attempted or the mutex is invalid
+ {
+ // Attempt to lock the access to the audio device, wait up to 1 second for other threads to unlock.
+ std::unique_lock lock(gAudioDeviceMutex, 1s);
+ // If the lock could not be accessed, return as we don't have hardware access and will need to try again another pass.
+ // Prevents threads from interacting with the hardware at the same time as other audio/voice threads.
+ if (!lock.owns_lock())
+ {
+ return;
+ }
+ // [FIRE-36022]
if (!mDeviceModule)
{
+ // [FIRE-36022]
+ // If the device is not avaiable, then make sure the flag for the WebRTC updated devices flag is turned off for the co-routine
+ gWebRTCUpdateDevices = false;
+ // [FIRE-36022] - Removing my USB headset crashes entire viewer
return;
}
@@ -489,6 +522,10 @@ void LLWebRTCImpl::workerDeployDevices()
}
}
+ // [FIRE-36022] - Removing my USB headset crashes entire viewer
+ // Flag the device is being interacted with for the Co-routine in case something goes wrong.
+ gWebRTCUpdateDevices = true;
+ // [FIRE-36022]
mDeviceModule->StopPlayout();
mDeviceModule->ForceStopRecording();
#if WEBRTC_WIN
@@ -552,6 +589,10 @@ void LLWebRTCImpl::workerDeployDevices()
{
mDeviceModule->StartPlayout();
}
+ // [FIRE-36022] - Removing my USB headset crashes entire viewer
+ // Finally signal to the co-routine everyting is OK.
+ gWebRTCUpdateDevices = false;
+ // [FIRE-36022]
mSignalingThread->PostTask(
[this]
{
@@ -572,6 +613,38 @@ void LLWebRTCImpl::workerDeployDevices()
mWorkerThread->PostTask([this] { workerDeployDevices(); });
}
});
+ // [FIRE-36022] - Removing my USB headset crashes entire viewer
+ }
+ // There are two exceptions that unique_lock can trigger, operation_not_permitted or resource_deadlock_would_occur
+ catch (const std::system_error& e)
+ {
+ if (e.code() == std::errc::resource_deadlock_would_occur)
+ {
+ // Another thead may have alreayd called this method
+ mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
+ }
+ else if (e.code() == std::errc::operation_not_permitted)
+ {
+ // This should not be reached
+ mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
+ }
+ else
+ {
+ // Log any other message
+ mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
+ }
+ // Device no longer being interacted with
+ gWebRTCUpdateDevices = false;
+ return;
+ }
+ catch (const std::exception& e)
+ {
+ mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
+ // Device no longer being interacted with
+ gWebRTCUpdateDevices = false;
+ return;
+ }
+ // [FIRE-36022]
}
void LLWebRTCImpl::setCaptureDevice(const std::string &id)
@@ -596,11 +669,27 @@ void LLWebRTCImpl::setRenderDevice(const std::string &id)
// updateDevices needs to happen on the worker thread.
void LLWebRTCImpl::updateDevices()
{
+ // [FIRE-36022] - Removing my USB headset crashes entire viewer
+ try // Try catch needed for uniquie lock as will throw an exception if a second lock is attempted or the mutex is invalid
+ {
+ // Attempt to lock the access to the audio device, wait up to 1 second for other threads to unlock.
+ std::unique_lock lock(gAudioDeviceMutex, 1s);
+ // If the lock could not be accessed, return as we don't have hardware access and will need to try again another pass.
+ // Prevents threads from interacting with the hardware at the same time as other audio/voice threads.
+ if (!lock.owns_lock())
+ {
+ return;
+ }
+ // [FIRE-36022]
if (!mDeviceModule)
{
return;
}
+ // [FIRE-36022] - Removing my USB headset crashes entire viewer
+ // Flag the device is being interacted with for the Co-routine in case something goes wrong.
+ gWebRTCUpdateDevices = true;
+ // [FIRE-36022]
int16_t renderDeviceCount = mDeviceModule->PlayoutDevices();
mPlayoutDeviceList.clear();
@@ -637,10 +726,46 @@ void LLWebRTCImpl::updateDevices()
mRecordingDeviceList.emplace_back(name, guid);
}
+ // [FIRE-36022] - Removing my USB headset crashes entire viewer
+ // Flag the device is no longer being interacted with for the Co-routine in case something goes wrong.
+ gWebRTCUpdateDevices = false;
+ // [FIRE-36022]
for (auto &observer : mVoiceDevicesObserverList)
{
observer->OnDevicesChanged(mPlayoutDeviceList, mRecordingDeviceList);
}
+ // [FIRE-36022] - Removing my USB headset crashes entire viewer
+ }
+ // There are two exceptions that unique_lock can trigger, operation_not_permitted or resource_deadlock_would_occur
+ catch (const std::system_error& e)
+ {
+ if (e.code() == std::errc::resource_deadlock_would_occur)
+ {
+ // Another thead may have alreayd called this method
+ mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
+ }
+ else if (e.code() == std::errc::operation_not_permitted)
+ {
+ // This should not be reached
+ mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
+ }
+ else
+ {
+ // Log any other message
+ mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
+ }
+ // Device no longer being interacted with
+ gWebRTCUpdateDevices = false;
+ return;
+ }
+ catch (const std::exception& e)
+ {
+ mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
+ // Device no longer being interacted with
+ gWebRTCUpdateDevices = false;
+ return;
+ }
+ // [FIRE-36022]
}
void LLWebRTCImpl::OnDevicesUpdated()
@@ -745,7 +870,56 @@ void LLWebRTCImpl::intSetMute(bool mute, int delay_ms)
{
if (mDeviceModule)
{
+ // [FIRE-36022] - Removing my USB headset crashes entire viewer
+ try // Try catch needed for uniquie lock as will throw an exception if a second lock is attempted or the mutex is
+ // invalid
+ {
+ // Attempt to lock the access to the audio device, wait up to 1 second for other threads to unlock.
+ std::unique_lock lock(gAudioDeviceMutex, 1s);
+ // If the lock could not be accessed, return as we don't have hardware access and will need to try again another pass.
+ // Prevents threads from interacting with the hardware at the same time as other audio/voice threads.
+ if (!lock.owns_lock())
+ {
+ return;
+ }
+ // Flag the device is being interacted with for the Co-routine in case something goes wrong.
+ gWebRTCUpdateDevices = true;
+ // [FIRE-36022]
mDeviceModule->ForceStopRecording();
+ // [FIRE-36022] - Removing my USB headset crashes entire viewer
+ // Finally signal to the co-routine everyting is OK.
+ gWebRTCUpdateDevices = false;
+ }
+ // There are two exceptions that unique_lock can trigger, operation_not_permitted or resource_deadlock_would_occur
+ catch (const std::system_error& e)
+ {
+ if (e.code() == std::errc::resource_deadlock_would_occur)
+ {
+ // Another thead may have alreayd called this method
+ mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
+ }
+ else if (e.code() == std::errc::operation_not_permitted)
+ {
+ // This should not be reached
+ mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
+ }
+ else
+ {
+ // Log any other message
+ mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
+ }
+ // Device no longer being interacted with
+ gWebRTCUpdateDevices = false;
+ return;
+ }
+ catch (const std::exception& e)
+ {
+ mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
+ // Device no longer being interacted with
+ gWebRTCUpdateDevices = false;
+ return;
+ }
+ // [FIRE-36022]
}
},
webrtc::TimeDelta::Millis(delay_ms));
@@ -757,8 +931,57 @@ void LLWebRTCImpl::intSetMute(bool mute, int delay_ms)
{
if (mDeviceModule)
{
+ // [FIRE-36022] - Removing my USB headset crashes entire viewer
+ try // Try catch needed for uniquie lock as will throw an exception if a second lock is attempted or the mutex is
+ // invalid
+ {
+ // Attempt to lock the access to the audio device, wait up to 1 second for other threads to unlock.
+ std::unique_lock lock(gAudioDeviceMutex, 1s);
+ // If the lock could not be accessed, return as we don't have hardware access and will need to try again another pass.
+ // Prevents threads from interacting with the hardware at the same time as other audio/voice threads.
+ if (!lock.owns_lock())
+ {
+ return;
+ }
+ // Flag the device is being interacted with for the Co-routine in case something goes wrong.
+ gWebRTCUpdateDevices = true;
+ // [FIRE-36022]
mDeviceModule->InitRecording();
mDeviceModule->ForceStartRecording();
+ // [FIRE-36022] - Removing my USB headset crashes entire viewer
+ // Finally signal to the co-routine everyting is OK.
+ gWebRTCUpdateDevices = false;
+ }
+ // There are two exceptions that unique_lock can trigger, operation_not_permitted or resource_deadlock_would_occur
+ catch (const std::system_error& e)
+ {
+ if (e.code() == std::errc::resource_deadlock_would_occur)
+ {
+ // Another thead may have alreayd called this method
+ mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
+ }
+ else if (e.code() == std::errc::operation_not_permitted)
+ {
+ // This should not be reached
+ mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
+ }
+ else
+ {
+ // Log any other message
+ mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
+ }
+ // Device no longer being interacted with
+ gWebRTCUpdateDevices = false;
+ return;
+ }
+ catch (const std::exception& e)
+ {
+ mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
+ // Device no longer being interacted with
+ gWebRTCUpdateDevices = false;
+ return;
+ }
+ // [FIRE-36022]
}
});
}
diff --git a/indra/llwebrtc/llwebrtc.h b/indra/llwebrtc/llwebrtc.h
index 7d06b7d2b4..acd3b686fa 100644
--- a/indra/llwebrtc/llwebrtc.h
+++ b/indra/llwebrtc/llwebrtc.h
@@ -40,6 +40,10 @@
#include
#include
+// [FIRE-36022] - Removing my USB headset crashes entire viewer
+// Needed for inline variable for the crash check
+#include
+// [FIRE-36022]
#ifdef LL_MAKEDLL
#ifdef WEBRTC_WIN
@@ -53,6 +57,12 @@
#define LLSYMEXPORT /**/
#endif // LL_MAKEDLL
+// [FIRE-36022] - Removing my USB headset crashes entire viewer
+// Create an atomic inline flag that will be shared between the various WebRTC threads and co-routines
+// to track of when the audio hardware is being talked to. The co-routine can use it to
+// exit if it too many iterations with the hardware locked indicating that the worker thread died.
+inline std::atomic gWebRTCUpdateDevices = false;
+// [FIRE-36022]
namespace llwebrtc
{
diff --git a/indra/newview/Info-Firestorm.plist b/indra/newview/Info-Firestorm.plist
index 6b2e73a5a2..add3bef56b 100644
--- a/indra/newview/Info-Firestorm.plist
+++ b/indra/newview/Info-Firestorm.plist
@@ -11,7 +11,7 @@
CFBundleIconFile
${MACOSX_BUNDLE_ICON_FILE}
CFBundleIdentifier
- ${PRODUCT_BUNDLE_IDENTIFIER}
+ $(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleLongVersionString
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 2140d0e4eb..1599b93056 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -23499,7 +23499,7 @@ Change of this parameter will affect the layout of buttons in notification toast
InventoryAddAttachmentBehavior
+ FSBuildPrefs_UseCustomScript
+
+ FSBuildPrefs_CustomScriptItem
+
FSllOwnerSayToScriptDebugWindow
Recent Items
Worn Items
+ Favorites
A group member named [NAME]
(online)
diff --git a/indra/newview/skins/default/xui/es/panel_preferences_firestorm.xml b/indra/newview/skins/default/xui/es/panel_preferences_firestorm.xml
index 1bb878354a..d14a0557db 100644
--- a/indra/newview/skins/default/xui/es/panel_preferences_firestorm.xml
+++ b/indra/newview/skins/default/xui/es/panel_preferences_firestorm.xml
@@ -129,33 +129,41 @@
Actualmente establecido a: [ITEM]
+
+
+ Drop a script here.
+
+
+ Actualmente establecido a: [SCRIPT]
+
+
+
+
+
Punto de pivotaje
-
+
+
+
+
+
+
+
-
+
Ruta include del preprocesador:
-
-
-
-
-
-
-
-
-
diff --git a/indra/newview/skins/default/xui/fr/floater_inventory_settings.xml b/indra/newview/skins/default/xui/fr/floater_inventory_settings.xml
index 4ae4c3db45..e0a1120f0c 100644
--- a/indra/newview/skins/default/xui/fr/floater_inventory_settings.xml
+++ b/indra/newview/skins/default/xui/fr/floater_inventory_settings.xml
@@ -22,5 +22,17 @@
-
+
+ Favoris
+
+
+
+
+
+ Appuyer sur Entrée sur un élément attaché à l'avatar
+
+
+
+
+
diff --git a/indra/newview/skins/default/xui/fr/floater_snapshot_guide_settings.xml b/indra/newview/skins/default/xui/fr/floater_snapshot_guide_settings.xml
new file mode 100644
index 0000000000..3ec00f7141
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/floater_snapshot_guide_settings.xml
@@ -0,0 +1,19 @@
+
+
+
+ Couleur et apparence du guide
+
+
+
+
+ Style du guide
+
+
+
+
+
+
+
+
+
+
diff --git a/indra/newview/skins/default/xui/fr/menu_gallery_inventory.xml b/indra/newview/skins/default/xui/fr/menu_gallery_inventory.xml
index c7a2d65ed9..e36cc2dc7a 100644
--- a/indra/newview/skins/default/xui/fr/menu_gallery_inventory.xml
+++ b/indra/newview/skins/default/xui/fr/menu_gallery_inventory.xml
@@ -51,6 +51,8 @@
+
+
diff --git a/indra/newview/skins/default/xui/pl/menu_url_objectim.xml b/indra/newview/skins/default/xui/pl/menu_url_objectim.xml
index d0996154bf..57e02eb0e3 100644
--- a/indra/newview/skins/default/xui/pl/menu_url_objectim.xml
+++ b/indra/newview/skins/default/xui/pl/menu_url_objectim.xml
@@ -3,6 +3,7 @@
+
diff --git a/indra/newview/skins/default/xui/pl/notifications.xml b/indra/newview/skins/default/xui/pl/notifications.xml
index 8d6a835f10..e98f9a1c6e 100644
--- a/indra/newview/skins/default/xui/pl/notifications.xml
+++ b/indra/newview/skins/default/xui/pl/notifications.xml
@@ -809,6 +809,15 @@ Oczekiwane: [VALIDS]
Nie można otworzyć przesłanego pliku dźwiękowego:
[FILE]
+
+ Przesyłanie modeli nie jest jeszcze dostępne na Apple Silicon, ale będzie obsługiwane w nadchodzącym wydaniu.
+
+Obejście: Kliknij prawym przyciskiem myszy aplikację [APP_NAME] w Finderze,
+wybierz "Pobierz info", a następnie zaznacz "Otwórz przy użyciu Rosetty".
+
+
+ Biblioteka fizyki nie jest obecna, dlatego część funkcji narzędzia przesyłania modeli może nie działać lub nie działać poprawnie.
+
Plik nie jest w formacie RIFF WAVE:
[FILE]
@@ -5042,6 +5051,10 @@ Będzie można użyć http://opensimulator.org/wiki/inventory aby rozwiązać pr
Nie można przenieść plików. Przywrócono poprzednią ścieżkę.
+
+ Twój system ma [TOTAL_MEM]MB pamięci, co może nie wystarczyć do uruchamiania przeglądarki na wyższych ustawieniach i może powodować problemy.
+
+
Wystąpił problem z zapisywaniem domyślnych zezwoleń obiektu: [REASON]. Spróbuj ustawić je ponownie później.
diff --git a/indra/newview/skins/default/xui/pl/panel_people.xml b/indra/newview/skins/default/xui/pl/panel_people.xml
index a0a5e707e9..3fbba990b2 100644
--- a/indra/newview/skins/default/xui/pl/panel_people.xml
+++ b/indra/newview/skins/default/xui/pl/panel_people.xml
@@ -54,6 +54,7 @@ Dowiedz się więcej o [https://community.secondlife.com/knowledgebase/joining-a
+
diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_firestorm.xml b/indra/newview/skins/default/xui/pl/panel_preferences_firestorm.xml
index 3c94a8f987..075bc88ca8 100644
--- a/indra/newview/skins/default/xui/pl/panel_preferences_firestorm.xml
+++ b/indra/newview/skins/default/xui/pl/panel_preferences_firestorm.xml
@@ -156,42 +156,17 @@
Obecnie: [ITEM]
-
- Punkt obracania osi
+
+
+ Upuść skrypt w tym miejscu.
+
+
+ Obecnie: [SCRIPT]
-
-
-
-
-
-
- Czcionka edytora skryptów:
-
-
-
-
-
-
-
-
-
-
-
-
-
- Ścieżka dołączania preprocesora:
-
-
-
- Zewnętrzny edytor:
-
-
-
-
-
+
@@ -208,8 +183,17 @@
części
-
+
+ Punkt obracania osi
+
+
+
+
+
+
+
+
@@ -218,6 +202,31 @@
+
+
+ Czcionka edytora skryptów:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Ścieżka dołączania preprocesora:
+
+
+
+ Zewnętrzny edytor:
+
+
+
Obecne lokalizacje dla nowych plików:
diff --git a/indra/newview/skins/default/xui/pl/strings.xml b/indra/newview/skins/default/xui/pl/strings.xml
index ba528b65e3..1c52481fd2 100644
--- a/indra/newview/skins/default/xui/pl/strings.xml
+++ b/indra/newview/skins/default/xui/pl/strings.xml
@@ -6576,6 +6576,9 @@ Twoja aktualna pozycja: [AVATAR_POS]
Założone
+
+ Ulubione
+
Osoba z grupy o imieniu [NAME]
diff --git a/indra/newview/skins/default/xui/ru/floater_inventory_settings.xml b/indra/newview/skins/default/xui/ru/floater_inventory_settings.xml
index 4f1b942ea6..66ce178b38 100644
--- a/indra/newview/skins/default/xui/ru/floater_inventory_settings.xml
+++ b/indra/newview/skins/default/xui/ru/floater_inventory_settings.xml
@@ -32,7 +32,7 @@
Нажатие Enter при прикреплении аватара
-
-
+
+
diff --git a/indra/newview/skins/default/xui/ru/panel_preferences_firestorm.xml b/indra/newview/skins/default/xui/ru/panel_preferences_firestorm.xml
index f7bdcc0c05..55dc304a6f 100644
--- a/indra/newview/skins/default/xui/ru/panel_preferences_firestorm.xml
+++ b/indra/newview/skins/default/xui/ru/panel_preferences_firestorm.xml
@@ -157,44 +157,14 @@
Содержимое: [ITEM]
-
- Точка опоры
+
+
+ Drop a script here.
+
+
+ Содержимое: [SCRIPT]
-
-
-
-
-
-
- Шрифт скриптов:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Путь для препроцессора:
-
-
-
- Внешний Редактор:
-
-
-
-
@@ -214,8 +184,17 @@
объектов
-
+
+ Точка опоры
+
+
+
+
+
+
+
+
@@ -224,6 +203,36 @@
+
+
+ Шрифт скриптов:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Путь для препроцессора:
+
+
+
+ Внешний Редактор:
+
+
+
diff --git a/indra/newview/skins/default/xui/ru/strings.xml b/indra/newview/skins/default/xui/ru/strings.xml
index 3a74bc3438..f1abaf5625 100644
--- a/indra/newview/skins/default/xui/ru/strings.xml
+++ b/indra/newview/skins/default/xui/ru/strings.xml
@@ -6821,6 +6821,9 @@ ID объекта: [INSPECTING_KEY]
Надетые предметы
+
+ Избранные
+
Член группы по имени [NAME]
diff --git a/indra/newview/skins/default/xui/zh/floater_inventory_settings.xml b/indra/newview/skins/default/xui/zh/floater_inventory_settings.xml
index a0be5f740b..12d4f5671f 100644
--- a/indra/newview/skins/default/xui/zh/floater_inventory_settings.xml
+++ b/indra/newview/skins/default/xui/zh/floater_inventory_settings.xml
@@ -32,7 +32,7 @@
在化身附件上按下“Enter”鍵
-
-
+
+
\ No newline at end of file
diff --git a/indra/newview/skins/default/xui/zh/panel_preferences_firestorm.xml b/indra/newview/skins/default/xui/zh/panel_preferences_firestorm.xml
index 0bfd1ebf4c..ecc12a340f 100644
--- a/indra/newview/skins/default/xui/zh/panel_preferences_firestorm.xml
+++ b/indra/newview/skins/default/xui/zh/panel_preferences_firestorm.xml
@@ -110,13 +110,41 @@
將物件拖到此處
當前: [ITEM]
+
+ Drop a script here.
+ 當前: [SCRIPT]
+
+
+
+
+
+
+
+
+ 旋轉限制為以下倍數:
+
+ 度,如果「對齊到網格」未啟用
+
+ 個物件
+
+
軸心點
-
+
+
+
+
+
+
+
+
+
+
+
指令碼編輯器字型:
@@ -131,6 +159,7 @@
+
@@ -141,30 +170,6 @@
外部編輯器:
-
-
-
-
-
-
-
-
- 旋轉限制為以下倍數:
-
- 度,如果「對齊到網格」未啟用
-
- 個物件
-
-
-
-
-
-
-
-
-
-
-
上傳的目標檔案夾:
圖像
diff --git a/indra/newview/skins/default/xui/zh/strings.xml b/indra/newview/skins/default/xui/zh/strings.xml
index 90fe8ca8c6..5296088f08 100644
--- a/indra/newview/skins/default/xui/zh/strings.xml
+++ b/indra/newview/skins/default/xui/zh/strings.xml
@@ -7422,6 +7422,9 @@ SecondLife.com網站的「支援」部分
已穿物件
+
+ 收藏
+
群組成員名 [NAME]
diff --git a/indra/newview/skins/starlight/xui/en/panel_main_inventory.xml b/indra/newview/skins/starlight/xui/en/panel_main_inventory.xml
index 77b7206680..2213841452 100644
--- a/indra/newview/skins/starlight/xui/en/panel_main_inventory.xml
+++ b/indra/newview/skins/starlight/xui/en/panel_main_inventory.xml
@@ -274,7 +274,7 @@
bevel_style="none"
follows="all"
label="Favorites"
- help_topic="recent_inventory_tab"
+ help_topic="favorites_inventory_tab"
layout="topleft"
name="Favorites"
show_item_link_overlays="true"
diff --git a/indra/newview/skins/starlightcui/xui/en/panel_main_inventory.xml b/indra/newview/skins/starlightcui/xui/en/panel_main_inventory.xml
index e79530721a..d3c36df606 100644
--- a/indra/newview/skins/starlightcui/xui/en/panel_main_inventory.xml
+++ b/indra/newview/skins/starlightcui/xui/en/panel_main_inventory.xml
@@ -278,7 +278,7 @@
follows="all"
height="338"
label="Favorites"
- help_topic="recent_inventory_tab"
+ help_topic="favorites_inventory_tab"
layout="topleft"
name="Favorites"
show_item_link_overlays="true"
diff --git a/indra/newview/skins/vintage/xui/en/panel_main_inventory.xml b/indra/newview/skins/vintage/xui/en/panel_main_inventory.xml
index 44afa1a770..d9567c6345 100644
--- a/indra/newview/skins/vintage/xui/en/panel_main_inventory.xml
+++ b/indra/newview/skins/vintage/xui/en/panel_main_inventory.xml
@@ -871,7 +871,7 @@
bevel_style="in"
follows="all"
label="Favorites"
- help_topic="recent_inventory_tab"
+ help_topic="favorites_inventory_tab"
layout="topleft"
name="Favorites"
show_item_link_overlays="true">