diff --git a/.hgtags b/.hgtags index 4823c05504..96ea267be3 100755 --- a/.hgtags +++ b/.hgtags @@ -547,3 +547,4 @@ ac3b1332ad4f55b7182a8cbcc1254535a0069f75 5.1.7-release a3143db58a0f6b005232bf9018e7fef17ff9ec90 6.1.0-release 50f0ece62ddb5a244ecb6d00ef5a89d80ad50efa 6.1.1-release 82a89165e5929a6c3073d6cd60a543cb395f147b 6.2.0-release +706bdc7e25c6e6b8fb56f4a13fcce2936e70a79c 6.2.1-release diff --git a/doc/contributions.txt b/doc/contributions.txt index f4b96d55c5..5a53ba9172 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -374,6 +374,7 @@ Cinder Roxley STORM-2116 STORM-2127 STORM-2144 + SL-3404 Clara Young Coaldust Numbers VWR-1095 @@ -779,6 +780,7 @@ Jonathan Yap STORM-2100 STORM-2104 STORM-2142 + SL-10089 Kadah Coba STORM-1060 STORM-1843 @@ -1069,6 +1071,8 @@ Nicky Dasmijn STORM-2010 STORM-2082 MAINT-6665 + SL-10291 + SL-10293 Nicky Perian OPEN-1 STORM-1087 diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 42ad56f1b0..af41b9e460 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -35,6 +35,7 @@ set(llcommon_SOURCE_FILES llapp.cpp llapr.cpp llassettype.cpp + llatomic.cpp llbase32.cpp llbase64.cpp llbitpack.cpp @@ -135,6 +136,7 @@ set(llcommon_HEADER_FILES llapp.h llapr.h llassettype.h + llatomic.h llbase32.h llbase64.h llbitpack.h diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index a00a82aff0..c0213d7c16 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -153,7 +153,6 @@ const U8 SIM_ACCESS_DOWN = 254; const U8 SIM_ACCESS_MAX = SIM_ACCESS_ADULT; // attachment constants -const S32 MAX_AGENT_ATTACHMENTS = 38; const U8 ATTACHMENT_ADD = 0x80; // god levels diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index acd829d864..245c73e3a2 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -30,9 +30,8 @@ #include #include "llrun.h" #include "llsd.h" +#include // Forward declarations -template class LLAtomic32; -typedef LLAtomic32 LLAtomicU32; class LLErrorThread; class LLLiveFile; #if LL_LINUX diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index d353d06de2..29f0c7da9a 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -28,13 +28,12 @@ #include "linden_common.h" #include "llapr.h" +#include "llmutex.h" #include "apr_dso.h" #include "llthreadlocalstorage.h" apr_pool_t *gAPRPoolp = NULL; // Global APR memory pool LLVolatileAPRPool *LLAPRFile::sAPRFilePoolp = NULL ; //global volatile APR memory pool. -apr_thread_mutex_t *gLogMutexp = NULL; -apr_thread_mutex_t *gCallStacksLogMutexp = NULL; const S32 FULL_VOLATILE_APR_POOL = 1024 ; //number of references to LLVolatileAPRPool @@ -48,10 +47,6 @@ void ll_init_apr() if (!gAPRPoolp) { apr_pool_create(&gAPRPoolp, NULL); - - // Initialize the logging mutex - apr_thread_mutex_create(&gLogMutexp, APR_THREAD_MUTEX_UNNESTED, gAPRPoolp); - apr_thread_mutex_create(&gCallStacksLogMutexp, APR_THREAD_MUTEX_UNNESTED, gAPRPoolp); } if(!LLAPRFile::sAPRFilePoolp) @@ -75,23 +70,6 @@ void ll_cleanup_apr() LL_INFOS("APR") << "Cleaning up APR" << LL_ENDL; - if (gLogMutexp) - { - // Clean up the logging mutex - - // All other threads NEED to be done before we clean up APR, so this is okay. - apr_thread_mutex_destroy(gLogMutexp); - gLogMutexp = NULL; - } - if (gCallStacksLogMutexp) - { - // Clean up the logging mutex - - // All other threads NEED to be done before we clean up APR, so this is okay. - apr_thread_mutex_destroy(gCallStacksLogMutexp); - gCallStacksLogMutexp = NULL; - } - LLThreadLocalPointerBase::destroyAllThreadLocalStorage(); if (gAPRPoolp) @@ -168,26 +146,19 @@ apr_pool_t* LLAPRPool::getAPRPool() LLVolatileAPRPool::LLVolatileAPRPool(BOOL is_local, apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) : LLAPRPool(parent, size, releasePoolFlag), mNumActiveRef(0), - mNumTotalRef(0), - mMutexPool(NULL), - mMutexp(NULL) + mNumTotalRef(0) { //create mutex if(!is_local) //not a local apr_pool, that is: shared by multiple threads. { - apr_pool_create(&mMutexPool, NULL); // Create a pool for mutex - apr_thread_mutex_create(&mMutexp, APR_THREAD_MUTEX_UNNESTED, mMutexPool); + mMutexp.reset(new std::mutex()); } } LLVolatileAPRPool::~LLVolatileAPRPool() { //delete mutex - if(mMutexp) - { - apr_thread_mutex_destroy(mMutexp); - apr_pool_destroy(mMutexPool); - } + mMutexp.reset(); } // @@ -201,7 +172,7 @@ apr_pool_t* LLVolatileAPRPool::getAPRPool() apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool() { - LLScopedLock lock(mMutexp) ; + LLScopedLock lock(mMutexp.get()) ; mNumTotalRef++ ; mNumActiveRef++ ; @@ -216,7 +187,7 @@ apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool() void LLVolatileAPRPool::clearVolatileAPRPool() { - LLScopedLock lock(mMutexp) ; + LLScopedLock lock(mMutexp.get()); if(mNumActiveRef > 0) { @@ -250,44 +221,6 @@ BOOL LLVolatileAPRPool::isFull() { return mNumTotalRef > FULL_VOLATILE_APR_POOL ; } -//--------------------------------------------------------------------- -// -// LLScopedLock -// -LLScopedLock::LLScopedLock(apr_thread_mutex_t* mutex) : mMutex(mutex) -{ - if(mutex) - { - if(ll_apr_warn_status(apr_thread_mutex_lock(mMutex))) - { - mLocked = false; - } - else - { - mLocked = true; - } - } - else - { - mLocked = false; - } -} - -LLScopedLock::~LLScopedLock() -{ - unlock(); -} - -void LLScopedLock::unlock() -{ - if(mLocked) - { - if(!ll_apr_warn_status(apr_thread_mutex_unlock(mMutex))) - { - mLocked = false; - } - } -} //--------------------------------------------------------------------- diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index 1ac5c4e9b2..da50dda103 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -36,15 +36,22 @@ #include #include "llwin32headerslean.h" #include "apr_thread_proc.h" -#include "apr_thread_mutex.h" #include "apr_getopt.h" #include "apr_signal.h" -#include "apr_atomic.h" #include "llstring.h" -extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp; -extern apr_thread_mutex_t* gCallStacksLogMutexp; +#if LL_WINDOWS +#pragma warning (push) +#pragma warning (disable:4265) +#endif +// warning C4265: 'std::_Pad' : class has virtual functions, but destructor is not virtual + +#include + +#if LL_WINDOWS +#pragma warning (pop) +#endif struct apr_dso_handle_t; /** @@ -120,77 +127,9 @@ private: S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool. S32 mNumTotalRef ; //number of total pointers pointing to the apr_pool since last creating. - apr_thread_mutex_t *mMutexp; - apr_pool_t *mMutexPool; + std::unique_ptr mMutexp; } ; -/** - * @class LLScopedLock - * @brief Small class to help lock and unlock mutexes. - * - * This class is used to have a stack level lock once you already have - * an apr mutex handy. The constructor handles the lock, and the - * destructor handles the unlock. Instances of this class are - * not thread safe. - */ -class LL_COMMON_API LLScopedLock : private boost::noncopyable -{ -public: - /** - * @brief Constructor which accepts a mutex, and locks it. - * - * @param mutex An allocated APR mutex. If you pass in NULL, - * this wrapper will not lock. - */ - LLScopedLock(apr_thread_mutex_t* mutex); - - /** - * @brief Destructor which unlocks the mutex if still locked. - */ - ~LLScopedLock(); - - /** - * @brief Check lock. - */ - bool isLocked() const { return mLocked; } - - /** - * @brief This method unlocks the mutex. - */ - void unlock(); - -protected: - bool mLocked; - apr_thread_mutex_t* mMutex; -}; - -template class LLAtomic32 -{ -public: - LLAtomic32() {}; - LLAtomic32(Type x) {apr_atomic_set32(&mData, apr_uint32_t(x)); }; - ~LLAtomic32() {}; - - operator const Type() { apr_uint32_t data = apr_atomic_read32(&mData); return Type(data); } - - Type CurrentValue() const { apr_uint32_t data = apr_atomic_read32(const_cast< volatile apr_uint32_t* >(&mData)); return Type(data); } - - Type operator =(const Type& x) { apr_atomic_set32(&mData, apr_uint32_t(x)); return Type(mData); } - void operator -=(Type x) { apr_atomic_sub32(&mData, apr_uint32_t(x)); } - void operator +=(Type x) { apr_atomic_add32(&mData, apr_uint32_t(x)); } - Type operator ++(int) { return apr_atomic_inc32(&mData); } // Type++ - Type operator --(int) { return apr_atomic_dec32(&mData); } // approximately --Type (0 if final is 0, non-zero otherwise) - - Type operator ++() { return apr_atomic_inc32(&mData); } // Type++ - Type operator --() { return apr_atomic_dec32(&mData); } // approximately --Type (0 if final is 0, non-zero otherwise) - -private: - volatile apr_uint32_t mData; -}; - -typedef LLAtomic32 LLAtomicU32; -typedef LLAtomic32 LLAtomicS32; - // File IO convenience functions. // Returns NULL if the file fails to open, sets *sizep to file size if not NULL // abbreviated flags diff --git a/indra/llcommon/llatomic.cpp b/indra/llcommon/llatomic.cpp new file mode 100644 index 0000000000..93aba1f460 --- /dev/null +++ b/indra/llcommon/llatomic.cpp @@ -0,0 +1,28 @@ +/** + * @file llatomic.cpp + * + * $LicenseInfo:firstyear=2018&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2018, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llatomic.h" + +//============================================================================ diff --git a/indra/llcommon/llatomic.h b/indra/llcommon/llatomic.h new file mode 100644 index 0000000000..8de773846c --- /dev/null +++ b/indra/llcommon/llatomic.h @@ -0,0 +1,69 @@ +/** + * @file llatomic.h + * @brief Base classes for atomic. + * + * $LicenseInfo:firstyear=2018&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2018, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLATOMIC_H +#define LL_LLATOMIC_H + +#include "stdtypes.h" + +#include + +template > class LLAtomicBase +{ +public: + LLAtomicBase() {}; + LLAtomicBase(Type x) { mData.store(x); } + ~LLAtomicBase() {}; + + operator const Type() { return mData; } + + Type CurrentValue() const { return mData; } + + Type operator =(const Type& x) { mData.store(x); return mData; } + void operator -=(Type x) { mData -= x; } + void operator +=(Type x) { mData += x; } + Type operator ++(int) { return mData++; } + Type operator --(int) { return mData--; } + + Type operator ++() { return ++mData; } + Type operator --() { return --mData; } + +private: + AtomicType mData; +}; + +// Typedefs for specialized versions. Using std::atomic_(u)int32_t to get the optimzed implementation. +#ifdef LL_WINDOWS +typedef LLAtomicBase LLAtomicU32; +typedef LLAtomicBase LLAtomicS32; +#else +typedef LLAtomicBase LLAtomicU32; +typedef LLAtomicBase LLAtomicS32; +#endif + +typedef LLAtomicBase LLAtomicBool; + +#endif // LL_LLATOMIC_H diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 7cfd1409b1..335a0995fe 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -390,15 +390,22 @@ namespace { llifstream file(filename().c_str()); - if (file.is_open()) + if (!file.is_open()) { - LLSDSerialize::fromXML(configuration, file); + LL_WARNS() << filename() << " failed to open file; not changing configuration" << LL_ENDL; + return false; } - if (configuration.isUndefined()) + if (LLSDSerialize::fromXML(configuration, file) == LLSDParser::PARSE_FAILURE) { - LL_WARNS() << filename() << " missing, ill-formed," - " or simply undefined; not changing configuration" + LL_WARNS() << filename() << " parcing error; not changing configuration" << LL_ENDL; + return false; + } + + if (configuration.isUndefined() || !configuration.isMap() || configuration.emptyMap()) + { + LL_WARNS() << filename() << " missing, ill-formed, or simply undefined" + " content; not changing configuration" << LL_ENDL; return false; } @@ -860,19 +867,24 @@ namespace LLError setEnabledLogTypesMask(config["enabled-log-types-mask"].asInteger()); } - LLSD sets = config["settings"]; - LLSD::array_const_iterator a, end; - for (a = sets.beginArray(), end = sets.endArray(); a != end; ++a) - { - const LLSD& entry = *a; - - ELevel level = decodeLevel(entry["level"]); - - setLevels(s->mFunctionLevelMap, entry["functions"], level); - setLevels(s->mClassLevelMap, entry["classes"], level); - setLevels(s->mFileLevelMap, entry["files"], level); - setLevels(s->mTagLevelMap, entry["tags"], level); - } + if (config.has("settings") && config["settings"].isArray()) + { + LLSD sets = config["settings"]; + LLSD::array_const_iterator a, end; + for (a = sets.beginArray(), end = sets.endArray(); a != end; ++a) + { + const LLSD& entry = *a; + if (entry.isMap() && !entry.emptyMap()) + { + ELevel level = decodeLevel(entry["level"]); + + setLevels(s->mFunctionLevelMap, entry["functions"], level); + setLevels(s->mClassLevelMap, entry["classes"], level); + setLevels(s->mFileLevelMap, entry["files"], level); + setLevels(s->mTagLevelMap, entry["tags"], level); + } + } + } } } @@ -1136,6 +1148,9 @@ namespace } namespace { + LLMutex gLogMutex; + LLMutex gCallStacksLogMutex; + bool checkLevelMap(const LevelMap& map, const std::string& key, LLError::ELevel& level) { @@ -1175,56 +1190,6 @@ namespace { } return found_level; } - - class LogLock - { - public: - LogLock(); - ~LogLock(); - bool ok() const { return mOK; } - private: - bool mLocked; - bool mOK; - }; - - LogLock::LogLock() - : mLocked(false), mOK(false) - { - if (!gLogMutexp) - { - mOK = true; - return; - } - - const int MAX_RETRIES = 5; - for (int attempts = 0; attempts < MAX_RETRIES; ++attempts) - { - apr_status_t s = apr_thread_mutex_trylock(gLogMutexp); - if (!APR_STATUS_IS_EBUSY(s)) - { - mLocked = true; - mOK = true; - return; - } - - ms_sleep(1); - //apr_thread_yield(); - // Just yielding won't necessarily work, I had problems with - // this on Linux - doug 12/02/04 - } - - // We're hosed, we can't get the mutex. Blah. - std::cerr << "LogLock::LogLock: failed to get mutex for log" - << std::endl; - } - - LogLock::~LogLock() - { - if (mLocked) - { - apr_thread_mutex_unlock(gLogMutexp); - } - } } namespace LLError @@ -1232,8 +1197,8 @@ namespace LLError bool Log::shouldLog(CallSite& site) { - LogLock lock; - if (!lock.ok()) + LLMutexTrylock lock(&gLogMutex, 5); + if (!lock.isLocked()) { return false; } @@ -1283,11 +1248,11 @@ namespace LLError std::ostringstream* Log::out() { - LogLock lock; + LLMutexTrylock lock(&gLogMutex,5); // If we hit a logging request very late during shutdown processing, // when either of the relevant LLSingletons has already been deleted, // DO NOT resurrect them. - if (lock.ok() && ! (Settings::wasDeleted() || Globals::wasDeleted())) + if (lock.isLocked() && ! (Settings::wasDeleted() || Globals::wasDeleted())) { Globals* g = Globals::getInstance(); @@ -1303,8 +1268,8 @@ namespace LLError void Log::flush(std::ostringstream* out, char* message) { - LogLock lock; - if (!lock.ok()) + LLMutexTrylock lock(&gLogMutex,5); + if (!lock.isLocked()) { return; } @@ -1343,8 +1308,8 @@ namespace LLError void Log::flush(std::ostringstream* out, const CallSite& site) { - LogLock lock; - if (!lock.ok()) + LLMutexTrylock lock(&gLogMutex,5); + if (!lock.isLocked()) { return; } @@ -1514,69 +1479,6 @@ namespace LLError char** LLCallStacks::sBuffer = NULL ; S32 LLCallStacks::sIndex = 0 ; -#define SINGLE_THREADED 1 - - class CallStacksLogLock - { - public: - CallStacksLogLock(); - ~CallStacksLogLock(); - -#if SINGLE_THREADED - bool ok() const { return true; } -#else - bool ok() const { return mOK; } - private: - bool mLocked; - bool mOK; -#endif - }; - -#if SINGLE_THREADED - CallStacksLogLock::CallStacksLogLock() - { - } - CallStacksLogLock::~CallStacksLogLock() - { - } -#else - CallStacksLogLock::CallStacksLogLock() - : mLocked(false), mOK(false) - { - if (!gCallStacksLogMutexp) - { - mOK = true; - return; - } - - const int MAX_RETRIES = 5; - for (int attempts = 0; attempts < MAX_RETRIES; ++attempts) - { - apr_status_t s = apr_thread_mutex_trylock(gCallStacksLogMutexp); - if (!APR_STATUS_IS_EBUSY(s)) - { - mLocked = true; - mOK = true; - return; - } - - ms_sleep(1); - } - - // We're hosed, we can't get the mutex. Blah. - std::cerr << "CallStacksLogLock::CallStacksLogLock: failed to get mutex for log" - << std::endl; - } - - CallStacksLogLock::~CallStacksLogLock() - { - if (mLocked) - { - apr_thread_mutex_unlock(gCallStacksLogMutexp); - } - } -#endif - //static void LLCallStacks::allocateStackBuffer() { @@ -1605,8 +1507,8 @@ namespace LLError //static void LLCallStacks::push(const char* function, const int line) { - CallStacksLogLock lock; - if (!lock.ok()) + LLMutexTrylock lock(&gCallStacksLogMutex, 5); + if (!lock.isLocked()) { return; } @@ -1640,8 +1542,8 @@ namespace LLError //static void LLCallStacks::end(std::ostringstream* _out) { - CallStacksLogLock lock; - if (!lock.ok()) + LLMutexTrylock lock(&gCallStacksLogMutex, 5); + if (!lock.isLocked()) { return; } @@ -1662,8 +1564,8 @@ namespace LLError //static void LLCallStacks::print() { - CallStacksLogLock lock; - if (!lock.ok()) + LLMutexTrylock lock(&gCallStacksLogMutex, 5); + if (!lock.isLocked()) { return; } @@ -1700,8 +1602,8 @@ namespace LLError bool debugLoggingEnabled(const std::string& tag) { - LogLock lock; - if (!lock.ok()) + LLMutexTrylock lock(&gLogMutex, 5); + if (!lock.isLocked()) { return false; } diff --git a/indra/llcommon/llfixedbuffer.cpp b/indra/llcommon/llfixedbuffer.cpp index d394f179fb..bd4db8be84 100644 --- a/indra/llcommon/llfixedbuffer.cpp +++ b/indra/llcommon/llfixedbuffer.cpp @@ -31,7 +31,7 @@ LLFixedBuffer::LLFixedBuffer(const U32 max_lines) : LLLineBuffer(), mMaxLines(max_lines), - mMutex(NULL) + mMutex() { mTimer.reset(); } diff --git a/indra/llcommon/llinstancetracker.cpp b/indra/llcommon/llinstancetracker.cpp index 11fc53f8c8..3f990f4869 100644 --- a/indra/llcommon/llinstancetracker.cpp +++ b/indra/llcommon/llinstancetracker.cpp @@ -36,17 +36,16 @@ void LLInstanceTrackerBase::StaticBase::incrementDepth() { - apr_atomic_inc32(&sIterationNestDepth); + ++sIterationNestDepth; } void LLInstanceTrackerBase::StaticBase::decrementDepth() { llassert(sIterationNestDepth); - apr_atomic_dec32(&sIterationNestDepth); + --sIterationNestDepth; } U32 LLInstanceTrackerBase::StaticBase::getDepth() { - apr_uint32_t data = apr_atomic_read32(&sIterationNestDepth); - return data; + return sIterationNestDepth; } diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h index 910c8dbd99..363d0bcbd5 100644 --- a/indra/llcommon/llinstancetracker.h +++ b/indra/llcommon/llinstancetracker.h @@ -28,6 +28,7 @@ #ifndef LL_LLINSTANCETRACKER_H #define LL_LLINSTANCETRACKER_H +#include #include #include @@ -81,8 +82,12 @@ protected: void decrementDepth(); U32 getDepth(); private: - U32 sIterationNestDepth; - }; +#ifdef LL_WINDOWS + std::atomic_uint32_t sIterationNestDepth; +#else + std::atomic_uint sIterationNestDepth; +#endif + }; }; LL_COMMON_API void assert_main_thread(); diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp index 9c13ef9e30..75f43a4704 100644 --- a/indra/llcommon/llmutex.cpp +++ b/indra/llcommon/llmutex.cpp @@ -24,47 +24,22 @@ */ #include "linden_common.h" -#include "llapr.h" - -#include "apr_portable.h" #include "llmutex.h" #include "llthread.h" +#include "lltimer.h" //============================================================================ -LLMutex::LLMutex(apr_pool_t *poolp) : - mAPRMutexp(NULL), mCount(0), mLockingThread(NO_THREAD) +LLMutex::LLMutex() : + mCount(0), + mLockingThread(NO_THREAD) { - //if (poolp) - //{ - // mIsLocalPool = FALSE; - // mAPRPoolp = poolp; - //} - //else - { - mIsLocalPool = TRUE; - apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread - } - apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mAPRPoolp); } LLMutex::~LLMutex() { -#if MUTEX_DEBUG - //bad assertion, the subclass LLSignal might be "locked", and that's OK - //llassert_always(!isLocked()); // better not be locked! -#endif - if (ll_apr_is_initialized()) - { - apr_thread_mutex_destroy(mAPRMutexp); - if (mIsLocalPool) - { - apr_pool_destroy(mAPRPoolp); - } - } - mAPRMutexp = NULL; } @@ -76,7 +51,7 @@ void LLMutex::lock() return; } - apr_thread_mutex_lock(mAPRMutexp); + mMutex.lock(); #if MUTEX_DEBUG // Have to have the lock before we can access the debug info @@ -106,19 +81,18 @@ void LLMutex::unlock() #endif mLockingThread = NO_THREAD; - apr_thread_mutex_unlock(mAPRMutexp); + mMutex.unlock(); } bool LLMutex::isLocked() { - apr_status_t status = apr_thread_mutex_trylock(mAPRMutexp); - if (APR_STATUS_IS_EBUSY(status)) + if (!mMutex.try_lock()) { return true; } else { - apr_thread_mutex_unlock(mAPRMutexp); + mMutex.unlock(); return false; } } @@ -141,8 +115,7 @@ bool LLMutex::trylock() return true; } - apr_status_t status(apr_thread_mutex_trylock(mAPRMutexp)); - if (APR_STATUS_IS_EBUSY(status)) + if (!mMutex.try_lock()) { return false; } @@ -161,45 +134,95 @@ bool LLMutex::trylock() //============================================================================ -LLCondition::LLCondition(apr_pool_t *poolp) : - LLMutex(poolp) +LLCondition::LLCondition() : + LLMutex() { - // base class (LLMutex) has already ensured that mAPRPoolp is set up. - - apr_thread_cond_create(&mAPRCondp, mAPRPoolp); } LLCondition::~LLCondition() { - apr_thread_cond_destroy(mAPRCondp); - mAPRCondp = NULL; } void LLCondition::wait() { - if (!isLocked()) - { //mAPRMutexp MUST be locked before calling apr_thread_cond_wait - apr_thread_mutex_lock(mAPRMutexp); -#if MUTEX_DEBUG - // avoid asserts on destruction in non-release builds - U32 id = LLThread::currentID(); - mIsLocked[id] = TRUE; -#endif - } - apr_thread_cond_wait(mAPRCondp, mAPRMutexp); + std::unique_lock< std::mutex > lock(mMutex); + mCond.wait(lock); } void LLCondition::signal() { - apr_thread_cond_signal(mAPRCondp); + mCond.notify_one(); } void LLCondition::broadcast() { - apr_thread_cond_broadcast(mAPRCondp); + mCond.notify_all(); } + +LLMutexTrylock::LLMutexTrylock(LLMutex* mutex) + : mMutex(mutex), + mLocked(false) +{ + if (mMutex) + mLocked = mMutex->trylock(); +} + +LLMutexTrylock::LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms) + : mMutex(mutex), + mLocked(false) +{ + if (!mMutex) + return; + + for (U32 i = 0; i < aTries; ++i) + { + mLocked = mMutex->trylock(); + if (mLocked) + break; + ms_sleep(delay_ms); + } +} + +LLMutexTrylock::~LLMutexTrylock() +{ + if (mMutex && mLocked) + mMutex->unlock(); +} + + +//--------------------------------------------------------------------- +// +// LLScopedLock +// +LLScopedLock::LLScopedLock(std::mutex* mutex) : mMutex(mutex) +{ + if(mutex) + { + mutex->lock(); + mLocked = true; + } + else + { + mLocked = false; + } +} + +LLScopedLock::~LLScopedLock() +{ + unlock(); +} + +void LLScopedLock::unlock() +{ + if(mLocked) + { + mMutex->unlock(); + mLocked = false; + } +} + //============================================================================ diff --git a/indra/llcommon/llmutex.h b/indra/llcommon/llmutex.h index ea535cee86..f841d7f950 100644 --- a/indra/llcommon/llmutex.h +++ b/indra/llcommon/llmutex.h @@ -28,6 +28,19 @@ #define LL_LLMUTEX_H #include "stdtypes.h" +#include + +#if LL_WINDOWS +#pragma warning (push) +#pragma warning (disable:4265) +#endif +// 'std::_Pad' : class has virtual functions, but destructor is not virtual +#include +#include + +#if LL_WINDOWS +#pragma warning (pop) +#endif //============================================================================ @@ -37,10 +50,6 @@ #include #endif -struct apr_thread_mutex_t; -struct apr_pool_t; -struct apr_thread_cond_t; - class LL_COMMON_API LLMutex { public: @@ -49,7 +58,7 @@ public: NO_THREAD = 0xFFFFFFFF } e_locking_thread; - LLMutex(apr_pool_t *apr_poolp = NULL); // NULL pool constructs a new pool for the mutex + LLMutex(); virtual ~LLMutex(); void lock(); // blocks @@ -60,13 +69,10 @@ public: U32 lockingThread() const; //get ID of locking thread protected: - apr_thread_mutex_t *mAPRMutexp; + std::mutex mMutex; mutable U32 mCount; mutable U32 mLockingThread; - apr_pool_t *mAPRPoolp; - BOOL mIsLocalPool; - #if MUTEX_DEBUG std::map mIsLocked; #endif @@ -76,7 +82,7 @@ protected: class LL_COMMON_API LLCondition : public LLMutex { public: - LLCondition(apr_pool_t* apr_poolp); // Defaults to global pool, could use the thread pool as well. + LLCondition(); ~LLCondition(); void wait(); // blocks @@ -84,7 +90,7 @@ public: void broadcast(); protected: - apr_thread_cond_t* mAPRCondp; + std::condition_variable mCond; }; class LLMutexLock @@ -119,19 +125,9 @@ private: class LLMutexTrylock { public: - LLMutexTrylock(LLMutex* mutex) - : mMutex(mutex), - mLocked(false) - { - if (mMutex) - mLocked = mMutex->trylock(); - } - - ~LLMutexTrylock() - { - if (mMutex && mLocked) - mMutex->unlock(); - } + LLMutexTrylock(LLMutex* mutex); + LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms = 10); + ~LLMutexTrylock(); bool isLocked() const { @@ -142,4 +138,43 @@ private: LLMutex* mMutex; bool mLocked; }; -#endif // LL_LLTHREAD_H + +/** +* @class LLScopedLock +* @brief Small class to help lock and unlock mutexes. +* +* The constructor handles the lock, and the destructor handles +* the unlock. Instances of this class are not thread safe. +*/ +class LL_COMMON_API LLScopedLock : private boost::noncopyable +{ +public: + /** + * @brief Constructor which accepts a mutex, and locks it. + * + * @param mutex An allocated mutex. If you pass in NULL, + * this wrapper will not lock. + */ + LLScopedLock(std::mutex* mutex); + + /** + * @brief Destructor which unlocks the mutex if still locked. + */ + ~LLScopedLock(); + + /** + * @brief Check lock. + */ + bool isLocked() const { return mLocked; } + + /** + * @brief This method unlocks the mutex. + */ + void unlock(); + +protected: + bool mLocked; + std::mutex* mMutex; +}; + +#endif // LL_LLMUTEX_H diff --git a/indra/llcommon/llqueuedthread.h b/indra/llcommon/llqueuedthread.h index d3704b0fe2..5d3f873646 100644 --- a/indra/llcommon/llqueuedthread.h +++ b/indra/llcommon/llqueuedthread.h @@ -32,7 +32,7 @@ #include #include -#include "llapr.h" +#include "llatomic.h" #include "llthread.h" #include "llsimplehash.h" @@ -128,7 +128,7 @@ public: }; protected: - LLAtomic32 mStatus; + LLAtomicBase mStatus; U32 mPriority; U32 mFlags; }; @@ -198,7 +198,7 @@ public: protected: BOOL mThreaded; // if false, run on main thread and do updates during update() BOOL mStarted; // required when mThreaded is false to call startThread() from update() - LLAtomic32 mIdleThread; // request queue is empty (or we are quitting) and the thread is idle + LLAtomicBool mIdleThread; // request queue is empty (or we are quitting) and the thread is idle typedef std::set request_queue_t; request_queue_t mRequestQueue; diff --git a/indra/llcommon/llrefcount.cpp b/indra/llcommon/llrefcount.cpp index a638df2c7c..29a5ca6f24 100644 --- a/indra/llcommon/llrefcount.cpp +++ b/indra/llcommon/llrefcount.cpp @@ -29,25 +29,9 @@ #include "llerror.h" -#if LL_REF_COUNT_DEBUG -#include "llthread.h" -#include "llapr.h" -#endif - LLRefCount::LLRefCount(const LLRefCount& other) : mRef(0) { -#if LL_REF_COUNT_DEBUG - if(gAPRPoolp) - { - mMutexp = new LLMutex(gAPRPoolp) ; - } - else - { - mMutexp = NULL ; - } - mCrashAtUnlock = FALSE ; -#endif } LLRefCount& LLRefCount::operator=(const LLRefCount&) @@ -59,17 +43,6 @@ LLRefCount& LLRefCount::operator=(const LLRefCount&) LLRefCount::LLRefCount() : mRef(0) { -#if LL_REF_COUNT_DEBUG - if(gAPRPoolp) - { - mMutexp = new LLMutex(gAPRPoolp) ; - } - else - { - mMutexp = NULL ; - } - mCrashAtUnlock = FALSE ; -#endif } LLRefCount::~LLRefCount() @@ -78,87 +51,5 @@ LLRefCount::~LLRefCount() { LL_ERRS() << "deleting non-zero reference" << LL_ENDL; } - -#if LL_REF_COUNT_DEBUG - if(gAPRPoolp) - { - delete mMutexp ; - } -#endif } -#if LL_REF_COUNT_DEBUG -void LLRefCount::ref() const -{ - if(mMutexp) - { - if(mMutexp->isLocked()) - { - mCrashAtUnlock = TRUE ; - LL_ERRS() << "the mutex is locked by the thread: " << mLockedThreadID - << " Current thread: " << LLThread::currentID() << LL_ENDL ; - } - - mMutexp->lock() ; - mLockedThreadID = LLThread::currentID() ; - - mRef++; - - if(mCrashAtUnlock) - { - while(1); //crash here. - } - mMutexp->unlock() ; - } - else - { - mRef++; - } -} - -S32 LLRefCount::unref() const -{ - if(mMutexp) - { - if(mMutexp->isLocked()) - { - mCrashAtUnlock = TRUE ; - LL_ERRS() << "the mutex is locked by the thread: " << mLockedThreadID - << " Current thread: " << LLThread::currentID() << LL_ENDL ; - } - - mMutexp->lock() ; - mLockedThreadID = LLThread::currentID() ; - - llassert(mRef >= 1); - if (0 == --mRef) - { - if(mCrashAtUnlock) - { - while(1); //crash here. - } - mMutexp->unlock() ; - - delete this; - return 0; - } - - if(mCrashAtUnlock) - { - while(1); //crash here. - } - mMutexp->unlock() ; - return mRef; - } - else - { - llassert(mRef >= 1); - if (0 == --mRef) - { - delete this; - return 0; - } - return mRef; - } -} -#endif diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h index 1107973569..fb0411d27b 100644 --- a/indra/llcommon/llrefcount.h +++ b/indra/llcommon/llrefcount.h @@ -29,12 +29,7 @@ #include #include #include "llmutex.h" -#include "llapr.h" - -#define LL_REF_COUNT_DEBUG 0 -#if LL_REF_COUNT_DEBUG -class LLMutex ; -#endif +#include "llatomic.h" //---------------------------------------------------------------------------- // RefCount objects should generally only be accessed by way of LLPointer<>'s @@ -51,10 +46,6 @@ protected: public: LLRefCount(); -#if LL_REF_COUNT_DEBUG - void ref() const ; - S32 unref() const ; -#else inline void ref() const { mRef++; @@ -69,8 +60,7 @@ public: return 0; } return mRef; - } -#endif + } //NOTE: when passing around a const LLRefCount object, this can return different results // at different types, since mRef is mutable @@ -81,12 +71,6 @@ public: private: mutable S32 mRef; - -#if LL_REF_COUNT_DEBUG - LLMutex* mMutexp ; - mutable U32 mLockedThreadID ; - mutable BOOL mCrashAtUnlock ; -#endif }; @@ -123,8 +107,8 @@ public: void unref() { llassert(mRef >= 1); - if ((--mRef) == 0) // See note in llapr.h on atomic decrement operator return value. - { + if ((--mRef) == 0) + { // If we hit zero, the caller should be the only smart pointer owning the object and we can delete it. // It is technically possible for a vanilla pointer to mess this up, or another thread to // jump in, find this object, create another smart pointer and end up dangling, but if @@ -140,7 +124,7 @@ public: } private: - LLAtomic32< S32 > mRef; + LLAtomicS32 mRef; }; /** diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 1ef6c538ba..1f8d558fbe 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -268,10 +268,32 @@ LLOSInfo::LLOSInfo() : } } + S32 ubr = 0; // Windows 10 Update Build Revision, can be retrieved from a registry + if (mMajorVer == 10) + { + DWORD cbData(sizeof(DWORD)); + DWORD data(0); + HKEY key; + BOOL ret_code = RegOpenKeyExW(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), 0, KEY_READ, &key); + if (ERROR_SUCCESS == ret_code) + { + ret_code = RegQueryValueExW(key, L"UBR", 0, NULL, reinterpret_cast(&data), &cbData); + if (ERROR_SUCCESS == ret_code) + { + ubr = data; + } + } + } + mOSString = mOSStringSimple; if (mBuild > 0) { - mOSString += llformat("(Build %d)", mBuild); + mOSString += llformat("(Build %d", mBuild); + if (ubr > 0) + { + mOSString += llformat(".%d", ubr); + } + mOSString += ")"; } LLStringUtil::trim(mOSStringSimple); diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index f066e9a4cd..a4171729db 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -116,29 +116,27 @@ void LLThread::registerThreadID() // // Handed to the APR thread creation function // -void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap) +void LLThread::threadRun() { - LLThread *threadp = (LLThread *)datap; - #ifdef LL_WINDOWS - set_thread_name(-1, threadp->mName.c_str()); + set_thread_name(-1, mName.c_str()); #endif // for now, hard code all LLThreads to report to single master thread recorder, which is known to be running on main thread - threadp->mRecorder = new LLTrace::ThreadRecorder(*LLTrace::get_master_thread_recorder()); + mRecorder = new LLTrace::ThreadRecorder(*LLTrace::get_master_thread_recorder()); - sThreadID = threadp->mID; + sThreadID = mID; // Run the user supplied function do { try { - threadp->run(); + run(); } catch (const LLContinueError &e) { - LL_WARNS("THREAD") << "ContinueException on thread '" << threadp->mName << + LL_WARNS("THREAD") << "ContinueException on thread '" << mName << "' reentering run(). Error what is: '" << e.what() << "'" << LL_ENDL; //output possible call stacks to log file. LLError::LLCallStacks::print(); @@ -153,41 +151,27 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap //LL_INFOS() << "LLThread::staticRun() Exiting: " << threadp->mName << LL_ENDL; - delete threadp->mRecorder; - threadp->mRecorder = NULL; + delete mRecorder; + mRecorder = NULL; // We're done with the run function, this thread is done executing now. //NB: we are using this flag to sync across threads...we really need memory barriers here // Todo: add LLMutex per thread instead of flag? // We are using "while (mStatus != STOPPED) {ms_sleep();}" everywhere. - threadp->mStatus = STOPPED; - - return NULL; + mStatus = STOPPED; } LLThread::LLThread(const std::string& name, apr_pool_t *poolp) : mPaused(FALSE), mName(name), - mAPRThreadp(NULL), + mThreadp(NULL), mStatus(STOPPED), mRecorder(NULL) { mID = ++sIDIter; - - // Thread creation probably CAN be paranoid about APR being initialized, if necessary - if (poolp) - { - mIsLocalPool = FALSE; - mAPRPoolp = poolp; - } - else - { - mIsLocalPool = TRUE; - apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread - } - mRunCondition = new LLCondition(mAPRPoolp); - mDataLock = new LLMutex(mAPRPoolp); + mRunCondition = new LLCondition(); + mDataLock = new LLMutex(); mLocalAPRFilePoolp = NULL ; } @@ -217,7 +201,7 @@ void LLThread::shutdown() // Warning! If you somehow call the thread destructor from itself, // the thread will die in an unclean fashion! - if (mAPRThreadp) + if (mThreadp) { if (!isStopped()) { @@ -248,14 +232,19 @@ void LLThread::shutdown() { // This thread just wouldn't stop, even though we gave it time //LL_WARNS() << "LLThread::~LLThread() exiting thread before clean exit!" << LL_ENDL; - // Put a stake in its heart. - apr_thread_exit(mAPRThreadp, -1); + // Put a stake in its heart. (A very hostile method to force a thread to quit) +#if LL_WINDOWS + TerminateThread(mNativeHandle, 0); +#else + pthread_cancel(mNativeHandle); +#endif + delete mRecorder; mRecorder = NULL; mStatus = STOPPED; return; } - mAPRThreadp = NULL; + mThreadp = NULL; } delete mRunCondition; @@ -263,12 +252,6 @@ void LLThread::shutdown() delete mDataLock; mDataLock = NULL; - - if (mIsLocalPool && mAPRPoolp) - { - apr_pool_destroy(mAPRPoolp); - mAPRPoolp = 0; - } if (mRecorder) { @@ -287,19 +270,15 @@ void LLThread::start() // Set thread state to running mStatus = RUNNING; - apr_status_t status = - apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, mAPRPoolp); - - if(status == APR_SUCCESS) - { - // We won't bother joining - apr_thread_detach(mAPRThreadp); + try + { + mThreadp = new std::thread(std::bind(&LLThread::threadRun, this)); + mNativeHandle = mThreadp->native_handle(); } - else + catch (std::system_error& ex) { mStatus = STOPPED; - LL_WARNS() << "failed to start thread " << mName << LL_ENDL; - ll_apr_warn_status(status); + LL_WARNS() << "failed to start thread " << mName << " " << ex.what() << LL_ENDL; } } @@ -376,11 +355,7 @@ U32 LLThread::currentID() // static void LLThread::yield() { -#if LL_LINUX || LL_SOLARIS - sched_yield(); // annoyingly, apr_thread_yield is a noop on linux... -#else - apr_thread_yield(); -#endif + std::this_thread::yield(); } void LLThread::wake() @@ -413,7 +388,7 @@ void LLThreadSafeRefCount::initThreadSafeRefCount() { if (!sMutex) { - sMutex = new LLMutex(0); + sMutex = new LLMutex(); } } diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index dda7fa8ffb..863c9051f3 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -29,10 +29,10 @@ #include "llapp.h" #include "llapr.h" -#include "apr_thread_cond.h" #include "boost/intrusive_ptr.hpp" #include "llmutex.h" #include "llrefcount.h" +#include LL_COMMON_API void assert_main_thread(); @@ -86,7 +86,6 @@ public: // this kicks off the apr thread void start(void); - apr_pool_t *getAPRPool() { return mAPRPoolp; } LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; } U32 getID() const { return mID; } @@ -97,19 +96,18 @@ public: static void registerThreadID(); private: - BOOL mPaused; + bool mPaused; + std::thread::native_handle_type mNativeHandle; // for termination in case of issues // static function passed to APR thread creation routine - static void *APR_THREAD_FUNC staticRun(struct apr_thread_t *apr_threadp, void *datap); + void threadRun(); protected: std::string mName; class LLCondition* mRunCondition; LLMutex* mDataLock; - apr_thread_t *mAPRThreadp; - apr_pool_t *mAPRPoolp; - BOOL mIsLocalPool; + std::thread *mThreadp; EThreadStatus mStatus; U32 mID; LLTrace::ThreadRecorder* mRecorder; diff --git a/indra/llcommon/llthreadsafequeue.cpp b/indra/llcommon/llthreadsafequeue.cpp index 491f920c0f..bde36999ba 100644 --- a/indra/llcommon/llthreadsafequeue.cpp +++ b/indra/llcommon/llthreadsafequeue.cpp @@ -24,87 +24,6 @@ */ #include "linden_common.h" -#include -#include #include "llthreadsafequeue.h" -#include "llexception.h" - -// LLThreadSafeQueueImplementation -//----------------------------------------------------------------------------- - - -LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(apr_pool_t * pool, unsigned int capacity): - mOwnsPool(pool == 0), - mPool(pool), - mQueue(0) -{ - if(mOwnsPool) { - apr_status_t status = apr_pool_create(&mPool, 0); - if(status != APR_SUCCESS) LLTHROW(LLThreadSafeQueueError("failed to allocate pool")); - } else { - ; // No op. - } - - apr_status_t status = apr_queue_create(&mQueue, capacity, mPool); - if(status != APR_SUCCESS) LLTHROW(LLThreadSafeQueueError("failed to allocate queue")); -} - - -LLThreadSafeQueueImplementation::~LLThreadSafeQueueImplementation() -{ - if(mQueue != 0) { - if(apr_queue_size(mQueue) != 0) LL_WARNS() << - "terminating queue which still contains " << apr_queue_size(mQueue) << - " elements;" << "memory will be leaked" << LL_ENDL; - apr_queue_term(mQueue); - } - if(mOwnsPool && (mPool != 0)) apr_pool_destroy(mPool); -} - - -void LLThreadSafeQueueImplementation::pushFront(void * element) -{ - apr_status_t status = apr_queue_push(mQueue, element); - - if(status == APR_EINTR) { - LLTHROW(LLThreadSafeQueueInterrupt()); - } else if(status != APR_SUCCESS) { - LLTHROW(LLThreadSafeQueueError("push failed")); - } else { - ; // Success. - } -} - - -bool LLThreadSafeQueueImplementation::tryPushFront(void * element){ - return apr_queue_trypush(mQueue, element) == APR_SUCCESS; -} - - -void * LLThreadSafeQueueImplementation::popBack(void) -{ - void * element; - apr_status_t status = apr_queue_pop(mQueue, &element); - - if(status == APR_EINTR) { - LLTHROW(LLThreadSafeQueueInterrupt()); - } else if(status != APR_SUCCESS) { - LLTHROW(LLThreadSafeQueueError("pop failed")); - } else { - return element; - } -} - - -bool LLThreadSafeQueueImplementation::tryPopBack(void *& element) -{ - return apr_queue_trypop(mQueue, &element) == APR_SUCCESS; -} - - -size_t LLThreadSafeQueueImplementation::size() -{ - return apr_queue_size(mQueue); -} diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h index 45289ef0b4..b0bddac8e5 100644 --- a/indra/llcommon/llthreadsafequeue.h +++ b/indra/llcommon/llthreadsafequeue.h @@ -28,12 +28,20 @@ #define LL_LLTHREADSAFEQUEUE_H #include "llexception.h" +#include #include +#if LL_WINDOWS +#pragma warning (push) +#pragma warning (disable:4265) +#endif +// 'std::_Pad' : class has virtual functions, but destructor is not virtual +#include +#include -struct apr_pool_t; // From apr_pools.h -class LLThreadSafeQueueImplementation; // See below. - +#if LL_WINDOWS +#pragma warning (pop) +#endif // // A general queue exception. @@ -64,31 +72,6 @@ public: } }; - -struct apr_queue_t; // From apr_queue.h - - -// -// Implementation details. -// -class LL_COMMON_API LLThreadSafeQueueImplementation -{ -public: - LLThreadSafeQueueImplementation(apr_pool_t * pool, unsigned int capacity); - ~LLThreadSafeQueueImplementation(); - void pushFront(void * element); - bool tryPushFront(void * element); - void * popBack(void); - bool tryPopBack(void *& element); - size_t size(); - -private: - bool mOwnsPool; - apr_pool_t * mPool; - apr_queue_t * mQueue; -}; - - // // Implements a thread safe FIFO. // @@ -100,7 +83,7 @@ public: // If the pool is set to NULL one will be allocated and managed by this // queue. - LLThreadSafeQueue(apr_pool_t * pool = 0, unsigned int capacity = 1024); + LLThreadSafeQueue(U32 capacity = 1024); // Add an element to the front of queue (will block if the queue has // reached capacity). @@ -128,77 +111,103 @@ public: size_t size(); private: - LLThreadSafeQueueImplementation mImplementation; + std::deque< ElementT > mStorage; + U32 mCapacity; + + std::mutex mLock; + std::condition_variable mCapacityCond; + std::condition_variable mEmptyCond; }; - - // LLThreadSafeQueue //----------------------------------------------------------------------------- - template -LLThreadSafeQueue::LLThreadSafeQueue(apr_pool_t * pool, unsigned int capacity): - mImplementation(pool, capacity) +LLThreadSafeQueue::LLThreadSafeQueue(U32 capacity) : +mCapacity(capacity) { - ; // No op. } template void LLThreadSafeQueue::pushFront(ElementT const & element) { - ElementT * elementCopy = new ElementT(element); - try { - mImplementation.pushFront(elementCopy); - } catch (LLThreadSafeQueueInterrupt) { - delete elementCopy; - throw; - } + while (true) + { + std::unique_lock lock1(mLock); + + if (mStorage.size() < mCapacity) + { + mStorage.push_front(element); + mEmptyCond.notify_one(); + return; + } + + // Storage Full. Wait for signal. + mCapacityCond.wait(lock1); + } } template bool LLThreadSafeQueue::tryPushFront(ElementT const & element) { - ElementT * elementCopy = new ElementT(element); - bool result = mImplementation.tryPushFront(elementCopy); - if(!result) delete elementCopy; - return result; + std::unique_lock lock1(mLock, std::defer_lock); + if (!lock1.try_lock()) + return false; + + if (mStorage.size() >= mCapacity) + return false; + + mStorage.push_front(element); + mEmptyCond.notify_one(); + return true; } template ElementT LLThreadSafeQueue::popBack(void) { - ElementT * element = reinterpret_cast (mImplementation.popBack()); - ElementT result(*element); - delete element; - return result; + while (true) + { + std::unique_lock lock1(mLock); + + if (!mStorage.empty()) + { + ElementT value = mStorage.back(); + mStorage.pop_back(); + mCapacityCond.notify_one(); + return value; + } + + // Storage empty. Wait for signal. + mEmptyCond.wait(lock1); + } } template bool LLThreadSafeQueue::tryPopBack(ElementT & element) { - void * storedElement; - bool result = mImplementation.tryPopBack(storedElement); - if(result) { - ElementT * elementPtr = reinterpret_cast(storedElement); - element = *elementPtr; - delete elementPtr; - } else { - ; // No op. - } - return result; + std::unique_lock lock1(mLock, std::defer_lock); + if (!lock1.try_lock()) + return false; + + if (mStorage.empty()) + return false; + + element = mStorage.back(); + mStorage.pop_back(); + mCapacityCond.notify_one(); + return true; } template size_t LLThreadSafeQueue::size(void) { - return mImplementation.size(); + std::lock_guard lock(mLock); + return mStorage.size(); } - #endif diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp index d4af2c6b01..8f33d789eb 100644 --- a/indra/llcommon/lluuid.cpp +++ b/indra/llcommon/lluuid.cpp @@ -738,7 +738,7 @@ void LLUUID::getCurrentTime(uuid_time_t *timestamp) getSystemTime(&time_last); uuids_this_tick = uuids_per_tick; init = TRUE; - mMutex = new LLMutex(NULL); + mMutex = new LLMutex(); } uuid_time_t time_now = {0,0}; diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp index 4c197dc1d6..4b91b2caca 100644 --- a/indra/llcommon/llworkerthread.cpp +++ b/indra/llcommon/llworkerthread.cpp @@ -37,7 +37,7 @@ LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded, bool should_pause) : LLQueuedThread(name, threaded, should_pause) { - mDeleteMutex = new LLMutex(NULL); + mDeleteMutex = new LLMutex(); if(!mLocalAPRFilePoolp) { @@ -204,7 +204,7 @@ LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& na mWorkerClassName(name), mRequestHandle(LLWorkerThread::nullHandle()), mRequestPriority(LLWorkerThread::PRIORITY_NORMAL), - mMutex(NULL), + mMutex(), mWorkFlags(0) { if (!mWorkerThread) diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h index 09776816a8..b1a6f61360 100644 --- a/indra/llcommon/llworkerthread.h +++ b/indra/llcommon/llworkerthread.h @@ -33,7 +33,7 @@ #include #include "llqueuedthread.h" -#include "llapr.h" +#include "llatomic.h" #define USE_FRAME_CALLBACK_MANAGER 0 diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp index cc49a2af80..0f76ff23ea 100644 --- a/indra/llcorehttp/_httpoprequest.cpp +++ b/indra/llcorehttp/_httpoprequest.cpp @@ -555,6 +555,11 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service) // about 700 or so requests and starts issuing TCP RSTs to // new connections. Reuse the DNS lookups for even a few // seconds and no RSTs. + // + // -1 stores forever + // 0 never stores + // any other positive number specifies seconds + // supposedly curl 7.62.0 can use TTL by default, otherwise default is 60 seconds check_curl_easy_setopt(mCurlHandle, CURLOPT_DNS_CACHE_TIMEOUT, dnsCacheTimeout); if (gpolicy.mUseLLProxy) diff --git a/indra/llcorehttp/_httpservice.h b/indra/llcorehttp/_httpservice.h index ac518a5de7..d0c37ac195 100644 --- a/indra/llcorehttp/_httpservice.h +++ b/indra/llcorehttp/_httpservice.h @@ -31,7 +31,7 @@ #include #include "linden_common.h" -#include "llapr.h" +#include "llatomic.h" #include "httpcommon.h" #include "httprequest.h" #include "_httppolicyglobal.h" diff --git a/indra/llcorehttp/_refcounted.h b/indra/llcorehttp/_refcounted.h index 7f713f2298..5cc8914395 100644 --- a/indra/llcorehttp/_refcounted.h +++ b/indra/llcorehttp/_refcounted.h @@ -34,7 +34,7 @@ #include #include -#include "llapr.h" +#include "llatomic.h" namespace LLCoreInt diff --git a/indra/llcorehttp/_thread.h b/indra/llcorehttp/_thread.h index e058d660e5..22b7750bad 100644 --- a/indra/llcorehttp/_thread.h +++ b/indra/llcorehttp/_thread.h @@ -33,6 +33,7 @@ #include #include +#include "apr.h" // thread-related functions #include "_refcounted.h" namespace LLCoreInt diff --git a/indra/llcorehttp/httpcommon.cpp b/indra/llcorehttp/httpcommon.cpp index 1829062af6..7c93c54cdf 100644 --- a/indra/llcorehttp/httpcommon.cpp +++ b/indra/llcorehttp/httpcommon.cpp @@ -333,7 +333,7 @@ LLMutex *getCurlMutex() if (!sHandleMutexp) { - sHandleMutexp = new LLMutex(NULL); + sHandleMutexp = new LLMutex(); } return sHandleMutexp; @@ -389,7 +389,7 @@ void initialize() S32 mutex_count = CRYPTO_num_locks(); for (S32 i = 0; i < mutex_count; i++) { - sSSLMutex.push_back(LLMutex_ptr(new LLMutex(NULL))); + sSSLMutex.push_back(LLMutex_ptr(new LLMutex())); } CRYPTO_set_id_callback(&ssl_thread_id); CRYPTO_set_locking_callback(&ssl_locking_callback); diff --git a/indra/llcorehttp/tests/test_httprequest.hpp b/indra/llcorehttp/tests/test_httprequest.hpp index b450f3502e..e65588e48f 100644 --- a/indra/llcorehttp/tests/test_httprequest.hpp +++ b/indra/llcorehttp/tests/test_httprequest.hpp @@ -2903,6 +2903,13 @@ void HttpRequestTestObjectType::test<22>() set_test_name("BUG-2295"); +#if LL_WINDOWS && ADDRESS_SIZE == 64 + // teamcity win64 builds freeze on this test, if you figure out the cause, please fix it + if (getenv("TEAMCITY_PROJECT_NAME")) + { + skip("BUG-2295 - partial load on W64 causes freeze"); + } +#endif // Handler can be stack-allocated *if* there are no dangling // references to it after completion of this method. // Create before memory record as the string copy will bump numbers. @@ -2921,6 +2928,7 @@ void HttpRequestTestObjectType::test<22>() // options set options = HttpOptions::ptr_t(new HttpOptions()); options->setRetries(1); // Partial_File is retryable and can timeout in here + options->setDNSCacheTimeout(30); // Get singletons created HttpRequest::createService(); @@ -3091,7 +3099,11 @@ void HttpRequestTestObjectType::test<23>() set_test_name("HttpRequest GET 503s with 'Retry-After'"); #if LL_WINDOWS && ADDRESS_SIZE == 64 - skip("llcorehttp 503-with-retry test hangs on Windows 64"); + // teamcity win64 builds freeze on this test, if you figure out the cause, please fix it + if (getenv("TEAMCITY_PROJECT_NAME")) + { + skip("llcorehttp 503-with-retry test hangs on Windows 64"); + } #endif // This tests mainly that the code doesn't fall over if diff --git a/indra/llcrashlogger/llcrashlock.cpp b/indra/llcrashlogger/llcrashlock.cpp index 77abfbcf0f..18d164abde 100644 --- a/indra/llcrashlogger/llcrashlock.cpp +++ b/indra/llcrashlogger/llcrashlock.cpp @@ -27,6 +27,7 @@ #include "linden_common.h" +#include "llapr.h" // thread-related functions #include "llcrashlock.h" #include "lldir.h" #include "llsd.h" diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 1a4dd2ca99..680fbf548f 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -594,7 +594,7 @@ void LLImage::initClass(bool use_new_byte_range, S32 minimal_reverse_byte_range_ { sUseNewByteRange = use_new_byte_range; sMinimalReverseByteRangePercent = minimal_reverse_byte_range_percent; - sMutex = new LLMutex(NULL); + sMutex = new LLMutex(); } //static diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp index 4875fe7001..5f42fba866 100644 --- a/indra/llimage/llimageworker.cpp +++ b/indra/llimage/llimageworker.cpp @@ -35,7 +35,7 @@ LLImageDecodeThread::LLImageDecodeThread(bool threaded) : LLQueuedThread("imagedecode", threaded) { - mCreationMutex = new LLMutex(getAPRPool()); + mCreationMutex = new LLMutex(); } //virtual diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp index 3b8f08e0c6..89cdb1c6b9 100644 --- a/indra/llmath/llvolumemgr.cpp +++ b/indra/llmath/llvolumemgr.cpp @@ -48,7 +48,7 @@ LLVolumeMgr::LLVolumeMgr() { // the LLMutex magic interferes with easy unit testing, // so you now must manually call useMutex() to use it - //mDataMutex = new LLMutex(gAPRPoolp); + //mDataMutex = new LLMutex(); } LLVolumeMgr::~LLVolumeMgr() @@ -214,7 +214,7 @@ void LLVolumeMgr::useMutex() { if (!mDataMutex) { - mDataMutex = new LLMutex(gAPRPoolp); + mDataMutex = new LLMutex(); } } diff --git a/indra/llmessage/llbuffer.cpp b/indra/llmessage/llbuffer.cpp index d07d9980c3..1a0eceba0f 100644 --- a/indra/llmessage/llbuffer.cpp +++ b/indra/llmessage/llbuffer.cpp @@ -265,7 +265,7 @@ void LLBufferArray::setThreaded(bool threaded) { if(!mMutexp) { - mMutexp = new LLMutex(NULL); + mMutexp = new LLMutex(); } } else diff --git a/indra/llmessage/llproxy.cpp b/indra/llmessage/llproxy.cpp index 537efa69d8..5730a36267 100644 --- a/indra/llmessage/llproxy.cpp +++ b/indra/llmessage/llproxy.cpp @@ -48,7 +48,7 @@ static void tcp_close_channel(LLSocket::ptr_t* handle_ptr); // Close an open TCP LLProxy::LLProxy(): mHTTPProxyEnabled(false), - mProxyMutex(NULL), + mProxyMutex(), mUDPProxy(), mTCPProxy(), mHTTPProxy(), diff --git a/indra/llmessage/llproxy.h b/indra/llmessage/llproxy.h index 688dff7c83..87891901ad 100644 --- a/indra/llmessage/llproxy.h +++ b/indra/llmessage/llproxy.h @@ -298,7 +298,7 @@ private: private: // Is the HTTP proxy enabled? Safe to read in any thread, but do not write directly. // Instead use enableHTTPProxy() and disableHTTPProxy() instead. - mutable LLAtomic32 mHTTPProxyEnabled; + mutable LLAtomicBool mHTTPProxyEnabled; // Mutex to protect shared members in non-main thread calls to applyProxySettings(). mutable LLMutex mProxyMutex; diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp index 506ccc98a4..a2524e9804 100644 --- a/indra/llmessage/llpumpio.cpp +++ b/indra/llmessage/llpumpio.cpp @@ -54,11 +54,7 @@ // constants for poll timeout. if we are threading, we want to have a // longer poll timeout. -#if LL_THREADS_APR -static const S32 DEFAULT_POLL_TIMEOUT = 1000; -#else static const S32 DEFAULT_POLL_TIMEOUT = 0; -#endif // The default (and fallback) expiration time for chains const F32 DEFAULT_CHAIN_EXPIRY_SECS = 30.0f; @@ -169,8 +165,6 @@ LLPumpIO::LLPumpIO(apr_pool_t* pool) : mPool(NULL), mCurrentPool(NULL), mCurrentPoolReallocCount(0), - mChainsMutex(NULL), - mCallbackMutex(NULL), mCurrentChain(mRunningChains.end()) { mCurrentChain = mRunningChains.end(); @@ -194,9 +188,6 @@ bool LLPumpIO::addChain(const chain_t& chain, F32 timeout, bool has_curl_request { if(chain.empty()) return false; -#if LL_THREADS_APR - LLScopedLock lock(mChainsMutex); -#endif LLChainInfo info; info.mHasCurlRequest = has_curl_request; info.setTimeoutSeconds(timeout); @@ -234,9 +225,6 @@ bool LLPumpIO::addChain( if(!data) return false; if(links.empty()) return false; -#if LL_THREADS_APR - LLScopedLock lock(mChainsMutex); -#endif #if LL_DEBUG_PIPE_TYPE_IN_PUMP LL_DEBUGS() << "LLPumpIO::addChain() " << links[0].mPipe << " '" << typeid(*(links[0].mPipe)).name() << "'" << LL_ENDL; @@ -391,9 +379,6 @@ void LLPumpIO::clearLock(S32 key) // therefore won't be treading into deleted memory. I think we can // also clear the lock on the chain safely since the pump only // reads that value. -#if LL_THREADS_APR - LLScopedLock lock(mChainsMutex); -#endif mClearLocks.insert(key); } @@ -457,9 +442,6 @@ void LLPumpIO::pump(const S32& poll_timeout) PUMP_DEBUG; if(true) { -#if LL_THREADS_APR - LLScopedLock lock(mChainsMutex); -#endif // bail if this pump is paused. if(PAUSING == mState) { @@ -724,25 +706,10 @@ void LLPumpIO::pump(const S32& poll_timeout) END_PUMP_DEBUG; } -//bool LLPumpIO::respond(const chain_t& pipes) -//{ -//#if LL_THREADS_APR -// LLScopedLock lock(mCallbackMutex); -//#endif -// LLChainInfo info; -// links_t links; -// -// mPendingCallbacks.push_back(info); -// return true; -//} - bool LLPumpIO::respond(LLIOPipe* pipe) { if(NULL == pipe) return false; -#if LL_THREADS_APR - LLScopedLock lock(mCallbackMutex); -#endif LLChainInfo info; LLLinkInfo link; link.mPipe = pipe; @@ -761,10 +728,6 @@ bool LLPumpIO::respond( if(!data) return false; if(links.empty()) return false; -#if LL_THREADS_APR - LLScopedLock lock(mCallbackMutex); -#endif - // Add the callback response LLChainInfo info; info.mChainLinks = links; @@ -781,9 +744,6 @@ void LLPumpIO::callback() //LL_INFOS() << "LLPumpIO::callback()" << LL_ENDL; if(true) { -#if LL_THREADS_APR - LLScopedLock lock(mCallbackMutex); -#endif std::copy( mPendingCallbacks.begin(), mPendingCallbacks.end(), @@ -809,9 +769,6 @@ void LLPumpIO::callback() void LLPumpIO::control(LLPumpIO::EControl op) { -#if LL_THREADS_APR - LLScopedLock lock(mChainsMutex); -#endif switch(op) { case PAUSE: @@ -829,22 +786,11 @@ void LLPumpIO::control(LLPumpIO::EControl op) void LLPumpIO::initialize(apr_pool_t* pool) { if(!pool) return; -#if LL_THREADS_APR - // SJB: Windows defaults to NESTED and OSX defaults to UNNESTED, so use UNNESTED explicitly. - apr_thread_mutex_create(&mChainsMutex, APR_THREAD_MUTEX_UNNESTED, pool); - apr_thread_mutex_create(&mCallbackMutex, APR_THREAD_MUTEX_UNNESTED, pool); -#endif mPool = pool; } void LLPumpIO::cleanup() { -#if LL_THREADS_APR - if(mChainsMutex) apr_thread_mutex_destroy(mChainsMutex); - if(mCallbackMutex) apr_thread_mutex_destroy(mCallbackMutex); -#endif - mChainsMutex = NULL; - mCallbackMutex = NULL; if(mPollset) { // LL_DEBUGS() << "cleaning up pollset" << LL_ENDL; diff --git a/indra/llmessage/llpumpio.h b/indra/llmessage/llpumpio.h index d2c5d37571..b9eabee710 100644 --- a/indra/llmessage/llpumpio.h +++ b/indra/llmessage/llpumpio.h @@ -40,9 +40,6 @@ #include "lliopipe.h" #include "llrun.h" -// Define this to enable use with the APR thread library. -//#define LL_THREADS_APR 1 - // some simple constants to help with timeouts extern const F32 DEFAULT_CHAIN_EXPIRY_SECS; extern const F32 SHORT_CHAIN_EXPIRY_SECS; @@ -393,14 +390,6 @@ protected: apr_pool_t* mCurrentPool; S32 mCurrentPoolReallocCount; -#if LL_THREADS_APR - apr_thread_mutex_t* mChainsMutex; - apr_thread_mutex_t* mCallbackMutex; -#else - int* mChainsMutex; - int* mCallbackMutex; -#endif - protected: void initialize(apr_pool_t* pool); void cleanup(); diff --git a/indra/llplugin/llpluginmessagepipe.cpp b/indra/llplugin/llpluginmessagepipe.cpp index 9468696507..9766e1bfed 100644 --- a/indra/llplugin/llpluginmessagepipe.cpp +++ b/indra/llplugin/llpluginmessagepipe.cpp @@ -92,8 +92,8 @@ void LLPluginMessagePipeOwner::killMessagePipe(void) } LLPluginMessagePipe::LLPluginMessagePipe(LLPluginMessagePipeOwner *owner, LLSocket::ptr_t socket): - mInputMutex(gAPRPoolp), - mOutputMutex(gAPRPoolp), + mInputMutex(), + mOutputMutex(), mOutputStartIndex(0), mOwner(owner), mSocket(socket) diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index 0a8e58ac90..eb6cb1b503 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -80,11 +80,11 @@ protected: }; LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner): - mIncomingQueueMutex(gAPRPoolp) + mIncomingQueueMutex() { if(!sInstancesMutex) { - sInstancesMutex = new LLMutex(gAPRPoolp); + sInstancesMutex = new LLMutex(); } mOwner = owner; diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h index cf3288489a..51fa2f8079 100644 --- a/indra/llprimitive/llmodel.h +++ b/indra/llprimitive/llmodel.h @@ -154,7 +154,6 @@ public: void ClearFacesAndMaterials() { mVolumeFaces.clear(); mMaterialList.clear(); } std::string getName() const; - std::string getMetric() const {return mMetric;} EModelStatus getStatus() const {return mStatus;} static std::string getStatusString(U32 status) ; @@ -260,8 +259,6 @@ public: std::string mRequestedLabel; // name requested in UI, if any. std::string mLabel; // name computed from dae. - std::string mMetric; // user-supplied metric data for upload - LLVector3 mNormalizedScale; LLVector3 mNormalizedTranslation; diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index c69c059880..27d1bee9bd 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -1580,7 +1580,7 @@ bool LLPrimitive::getTESTAxes(const U8 face, U32* s_axis, U32* t_axis) *s_axis = VY; *t_axis = VZ; return true; } - else if (face == 5) + else if (face >= 5) { *s_axis = VX; *t_axis = VY; return true; diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 8054eb3619..e44f57fa9f 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -200,6 +200,7 @@ set(llui_HEADER_FILES llresizehandle.h llresmgr.h llrngwriter.h + llsearchablecontrol.h llsearcheditor.h llscrollbar.h llscrollcontainer.h diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 510a2537b9..6b7a8a8b86 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -769,6 +769,10 @@ void LLButton::draw() } } + // Highlight if needed + if( ll::ui::SearchableControl::getHighlighted() ) + label_color = ll::ui::SearchableControl::getHighlightColor(); + // Unselected label assignments LLWString label = getCurrentLabel(); diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index 7b4719866d..7629ed1fea 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -62,6 +62,7 @@ class LLUICtrlFactory; class LLButton : public LLUICtrl, public LLBadgeOwner +, public ll::ui::SearchableControl { public: struct Params @@ -380,6 +381,12 @@ protected: LLFlashTimer * mFlashingTimer; bool mForceFlashing; // Stick flashing color even if button is pressed bool mHandleRightMouse; + +protected: + virtual std::string _getSearchText() const + { + return getLabelUnselected() + getToolTip(); + } }; // Build time optimization, generate once in .cpp file diff --git a/indra/llui/llcheckboxctrl.h b/indra/llui/llcheckboxctrl.h index 5ce45b2135..07ae9c3b18 100644 --- a/indra/llui/llcheckboxctrl.h +++ b/indra/llui/llcheckboxctrl.h @@ -47,6 +47,7 @@ class LLViewBorder; class LLCheckBoxCtrl : public LLUICtrl +, public ll::ui::SearchableControl { public: struct Params @@ -92,6 +93,8 @@ public: // LLCheckBoxCtrl interface virtual BOOL toggle() { return mButton->toggleState(); } // returns new state + void setBtnFocus() { mButton->setFocus(TRUE); } + void setEnabledColor( const LLColor4 &color ) { mTextEnabledColor = color; } void setDisabledColor( const LLColor4 &color ) { mTextDisabledColor = color; } @@ -106,6 +109,18 @@ public: virtual BOOL isDirty() const; // Returns TRUE if the user has modified this control. virtual void resetDirty(); // Clear dirty state +protected: + virtual std::string _getSearchText() const + { + return getLabel() + getToolTip(); + } + + virtual void onSetHighlight() const // When highlight, really do highlight the label + { + if( mLabel ) + mLabel->ll::ui::SearchableControl::setHighlighted( ll::ui::SearchableControl::getHighlighted() ); + } + protected: // note: value is stored in toggle state of button LLButton* mButton; diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index 00a933a0bb..b2ad38bddf 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -243,7 +243,14 @@ LLScrollListItem* LLComboBox::add(const std::string& name, EAddPosition pos, BOO item->setEnabled(enabled); if (!mAllowTextEntry && mLabel.empty()) { - selectFirstItem(); + if (mControlVariable) + { + setValue(mControlVariable->getValue()); // selects the appropriate item + } + else + { + selectFirstItem(); + } } return item; } @@ -255,7 +262,14 @@ LLScrollListItem* LLComboBox::add(const std::string& name, const LLUUID& id, EAd item->setEnabled(enabled); if (!mAllowTextEntry && mLabel.empty()) { - selectFirstItem(); + if (mControlVariable) + { + setValue(mControlVariable->getValue()); // selects the appropriate item + } + else + { + selectFirstItem(); + } } return item; } @@ -268,7 +282,14 @@ LLScrollListItem* LLComboBox::add(const std::string& name, void* userdata, EAddP item->setUserdata( userdata ); if (!mAllowTextEntry && mLabel.empty()) { - selectFirstItem(); + if (mControlVariable) + { + setValue(mControlVariable->getValue()); // selects the appropriate item + } + else + { + selectFirstItem(); + } } return item; } @@ -280,7 +301,14 @@ LLScrollListItem* LLComboBox::add(const std::string& name, LLSD value, EAddPosit item->setEnabled(enabled); if (!mAllowTextEntry && mLabel.empty()) { - selectFirstItem(); + if (mControlVariable) + { + setValue(mControlVariable->getValue()); // selects the appropriate item + } + else + { + selectFirstItem(); + } } return item; } diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp index 69246a2f57..b1ba725c2f 100644 --- a/indra/llui/lllayoutstack.cpp +++ b/indra/llui/lllayoutstack.cpp @@ -251,8 +251,14 @@ void LLLayoutStack::draw() // always clip to stack itself LLLocalClipRect clip(getLocalRect()); - BOOST_FOREACH(LLLayoutPanel* panelp, mPanels) + for (LLLayoutPanel* panelp : mPanels) { + if ((!panelp->getVisible() || panelp->mCollapsed) + && (panelp->mVisibleAmt < 0.001f || !mAnimate)) + { + // essentially invisible + continue; + } // clip to layout rectangle, not bounding rectangle LLRect clip_rect = panelp->getRect(); // scale clipping rectangle by visible amount diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 0d42f726fa..92543b952e 100644 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -504,6 +504,10 @@ void LLMenuItemGL::draw( void ) color = mDisabledColor.get(); } + // Highlight if needed + if( ll::ui::SearchableControl::getHighlighted() ) + color = ll::ui::SearchableControl::getHighlightColor(); + // Draw the text on top. if (mBriefItem) { diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index 69f7d21513..78f688642e 100644 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -48,7 +48,7 @@ extern S32 MENU_BAR_WIDTH; // The LLMenuItemGL represents a single menu item in a menu. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLMenuItemGL : public LLUICtrl +class LLMenuItemGL: public LLUICtrl, public ll::ui::SearchableControl { public: struct Params : public LLInitParam::Block @@ -175,7 +175,12 @@ protected: // This function appends the character string representation of // the current accelerator key and mask to the provided string. void appendAcceleratorString( std::string& st ) const; - + + virtual std::string _getSearchText() const + { + return mLabel.getString(); + } + protected: KEY mAcceleratorKey; MASK mAcceleratorMask; diff --git a/indra/llui/llsearchablecontrol.h b/indra/llui/llsearchablecontrol.h new file mode 100644 index 0000000000..f7f1ffa0a5 --- /dev/null +++ b/indra/llui/llsearchablecontrol.h @@ -0,0 +1,71 @@ +/** +* @file llsearchablecontrol.h +* +* $LicenseInfo:firstyear=2019&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2019, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#ifndef LL_SEARCHABLE_CONTROL_H +#define LL_SEARCHABLE_CONTROL_H + +#include "lluicolortable.h" +#include "lluicolor.h" + +namespace ll +{ + namespace ui + { + class SearchableControl + { + mutable bool mIsHighlighed; + public: + SearchableControl() + : mIsHighlighed( false ) + { } + virtual ~SearchableControl() + { } + + LLColor4 getHighlightColor( ) const + { + static LLUIColor highlight_color = LLUIColorTable::instance().getColor("SearchableControlHighlightColor", LLColor4::red); + return highlight_color.get(); + } + + void setHighlighted( bool aVal ) const + { + mIsHighlighed = aVal; + onSetHighlight( ); + } + bool getHighlighted( ) const + { return mIsHighlighed; } + + std::string getSearchText() const + { return _getSearchText(); } + protected: + virtual std::string _getSearchText() const = 0; + virtual void onSetHighlight( ) const + { } + }; + } +} + + +#endif diff --git a/indra/llui/llsliderctrl.h b/indra/llui/llsliderctrl.h index 67cca9ef04..2bb8668b90 100644 --- a/indra/llui/llsliderctrl.h +++ b/indra/llui/llsliderctrl.h @@ -35,7 +35,7 @@ #include "lllineeditor.h" -class LLSliderCtrl : public LLF32UICtrl +class LLSliderCtrl: public LLF32UICtrl, public ll::ui::SearchableControl { public: struct Params : public LLInitParam::Block @@ -131,6 +131,19 @@ public: static void onEditorGainFocus(LLFocusableElement* caller, void *userdata); static void onEditorChangeFocus(LLUICtrl* caller, S32 direction, void *userdata); +protected: + virtual std::string _getSearchText() const + { + std::string strLabel; + if( mLabelBox ) + strLabel = mLabelBox->getLabel(); + return strLabel + getToolTip(); + } + virtual void onSetHighlight() const // When highlight, really do highlight the label + { + if( mLabelBox ) + mLabelBox->ll::ui::SearchableControl::setHighlighted( ll::ui::SearchableControl::getHighlighted() ); + } private: void updateText(); void reportInvalidData(); diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index 1b2f09cff5..6521b883f8 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -76,7 +76,8 @@ public: mButton(b), mOldState(FALSE), mPlaceholderText(placeholder), - mPadding(0) + mPadding(0), + mVisible(true) {} LLTabContainer* mTabContainer; @@ -85,6 +86,8 @@ public: BOOL mOldState; LLTextBox* mPlaceholderText; S32 mPadding; + + mutable bool mVisible; }; //---------------------------------------------------------------------------- @@ -398,7 +401,10 @@ void LLTabContainer::draw() { break; } - target_pixel_scroll += (*iter)->mButton->getRect().getWidth(); + + if( (*iter)->mVisible ) + target_pixel_scroll += (*iter)->mButton->getRect().getWidth(); + cur_scroll_pos--; } @@ -467,6 +473,12 @@ void LLTabContainer::draw() { LLTabTuple* tuple = *iter; + if( !tuple->mVisible ) + { + tuple->mButton->setVisible( false ); + continue; + } + tuple->mButton->translate( left ? left - tuple->mButton->getRect().mLeft : 0, top ? top - tuple->mButton->getRect().mTop : 0 ); if (top) top -= BTN_HEIGHT + tabcntrv_pad; @@ -724,11 +736,11 @@ BOOL LLTabContainer::handleToolTip( S32 x, S32 y, MASK mask) { for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) { - LLTabTuple* tuple = *iter; - tuple->mButton->setVisible( TRUE ); - S32 local_x = x - tuple->mButton->getRect().mLeft; - S32 local_y = y - tuple->mButton->getRect().mBottom; - handled = tuple->mButton->handleToolTip( local_x, local_y, mask); + LLButton* tab_button = (*iter)->mButton; + if (!tab_button->getVisible()) continue; + S32 local_x = x - tab_button->getRect().mLeft; + S32 local_y = y - tab_button->getRect().mBottom; + handled = tab_button->handleToolTip(local_x, local_y, mask); if( handled ) { break; @@ -1505,7 +1517,7 @@ BOOL LLTabContainer::setTab(S32 which) } BOOL is_visible = FALSE; - if (selected_tuple->mButton->getEnabled()) + if( selected_tuple->mButton->getEnabled() && selected_tuple->mVisible ) { setCurrentPanelIndex(which); @@ -2121,3 +2133,35 @@ S32 LLTabContainer::getTotalTabWidth() const { return mTotalTabWidth; } + +void LLTabContainer::setTabVisibility( LLPanel const *aPanel, bool aVisible ) +{ + for( tuple_list_t::const_iterator itr = mTabList.begin(); itr != mTabList.end(); ++itr ) + { + LLTabTuple const *pTT = *itr; + if( pTT->mTabPanel == aPanel ) + { + pTT->mVisible = aVisible; + break; + } + } + + bool foundTab( false ); + for( tuple_list_t::const_iterator itr = mTabList.begin(); itr != mTabList.end(); ++itr ) + { + LLTabTuple const *pTT = *itr; + if( pTT->mVisible ) + { + this->selectTab( itr - mTabList.begin() ); + foundTab = true; + break; + } + } + + if( foundTab ) + this->setVisible( TRUE ); + else + this->setVisible( FALSE ); + + updateMaxScrollPos(); +} diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h index 4a5f08f5d3..6bf963313c 100644 --- a/indra/llui/lltabcontainer.h +++ b/indra/llui/lltabcontainer.h @@ -216,6 +216,8 @@ public: S32 getMinTabWidth() const { return mMinTabWidth; } S32 getMaxTabWidth() const { return mMaxTabWidth; } + void setTabVisibility( LLPanel const *aPanel, bool ); + void startDragAndDropDelayTimer() { mDragAndDropDelayTimer.start(); } void onTabBtn( const LLSD& data, LLPanel* panel ); diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index c570285856..a23741b6dd 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -1222,6 +1222,17 @@ void LLTextBase::draw() gl_rect_2d(text_rect, bg_color % alpha, TRUE); } + // Draw highlighted if needed + if( ll::ui::SearchableControl::getHighlighted() ) + { + LLColor4 bg_color = ll::ui::SearchableControl::getHighlightColor(); + LLRect bg_rect = mVisibleTextRect; + if( mScroller ) + bg_rect.intersectWith( text_rect ); + + gl_rect_2d( text_rect, bg_color, TRUE ); + } + bool should_clip = mClip || mScroller != NULL; { LLLocalClipRect clip(text_rect, should_clip); diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 5fdde445ef..9831c35858 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -275,7 +275,8 @@ typedef LLPointer LLTextSegmentPtr; class LLTextBase : public LLUICtrl, protected LLEditMenuHandler, - public LLSpellCheckMenuHandler + public LLSpellCheckMenuHandler, + public ll::ui::SearchableControl { public: friend class LLTextSegment; @@ -617,6 +618,11 @@ protected: void appendAndHighlightTextImpl(const std::string &new_text, S32 highlight_part, const LLStyle::Params& style_params, bool underline_on_hover_only = false); S32 normalizeUri(std::string& uri); +protected: + virtual std::string _getSearchText() const + { + return mLabel.getString() + getToolTip(); + } protected: // text segmentation and flow diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 134b76c720..137167db2a 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -732,14 +732,30 @@ BOOL LLTextEditor::handleRightMouseDown(S32 x, S32 y, MASK mask) { setFocus(TRUE); } + + bool show_menu = false; + // Prefer editor menu if it has selection. See EXT-6806. - if (hasSelection() || !LLTextBase::handleRightMouseDown(x, y, mask)) + if (hasSelection()) { - if(getShowContextMenu()) + S32 click_pos = getDocIndexFromLocalCoord(x, y, FALSE); + if (click_pos > mSelectionStart && click_pos < mSelectionEnd) { - showContextMenu(x, y); + show_menu = true; } } + + // Let segments handle the click, if nothing does, show editor menu + if (!show_menu && !LLTextBase::handleRightMouseDown(x, y, mask)) + { + show_menu = true; + } + + if (show_menu && getShowContextMenu()) + { + showContextMenu(x, y); + } + return TRUE; } diff --git a/indra/llui/lluictrl.h b/indra/llui/lluictrl.h index e53ecd30c2..7360bd7659 100644 --- a/indra/llui/lluictrl.h +++ b/indra/llui/lluictrl.h @@ -37,6 +37,7 @@ #include "llinitparam.h" #include "llview.h" #include "llviewmodel.h" // *TODO move dependency to .cpp file +#include "llsearchablecontrol.h" const BOOL TAKE_FOCUS_YES = TRUE; const BOOL TAKE_FOCUS_NO = FALSE; diff --git a/indra/llvfs/lllfsthread.h b/indra/llvfs/lllfsthread.h index cdb5c75946..58f658f7ba 100644 --- a/indra/llvfs/lllfsthread.h +++ b/indra/llvfs/lllfsthread.h @@ -32,7 +32,6 @@ #include #include -#include "llapr.h" #include "llpointer.h" #include "llqueuedthread.h" diff --git a/indra/llvfs/llpidlock.cpp b/indra/llvfs/llpidlock.cpp index 6572edead3..f770e93d45 100644 --- a/indra/llvfs/llpidlock.cpp +++ b/indra/llvfs/llpidlock.cpp @@ -27,6 +27,7 @@ #include "linden_common.h" +#include "llapr.h" // thread-related functions #include "llpidlock.h" #include "lldir.h" #include "llsd.h" diff --git a/indra/llvfs/llvfs.cpp b/indra/llvfs/llvfs.cpp index d5bd1834c2..617056d94d 100644 --- a/indra/llvfs/llvfs.cpp +++ b/indra/llvfs/llvfs.cpp @@ -234,7 +234,7 @@ LLVFS::LLVFS(const std::string& index_filename, const std::string& data_filename mDataFP(NULL), mIndexFP(NULL) { - mDataMutex = new LLMutex(0); + mDataMutex = new LLMutex(); S32 i; for (i = 0; i < VFSLOCK_COUNT; i++) diff --git a/indra/llvfs/llvfsthread.h b/indra/llvfs/llvfsthread.h index 95f3c857c6..7814de4a2d 100644 --- a/indra/llvfs/llvfsthread.h +++ b/indra/llvfs/llvfsthread.h @@ -32,8 +32,6 @@ #include #include -#include "llapr.h" - #include "llqueuedthread.h" #include "llvfs.h" diff --git a/indra/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm index 54a4793b2d..33eed7227a 100644 --- a/indra/llwindow/llopenglview-objc.mm +++ b/indra/llwindow/llopenglview-objc.mm @@ -343,6 +343,10 @@ attributedStringInfo getSegments(NSAttributedString *str) - (void) mouseDown:(NSEvent *)theEvent { + NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow]; + mMousePos[0] = mPoint.x; + mMousePos[1] = mPoint.y; + // Apparently people still use this? if ([theEvent modifierFlags] & NSCommandKeyMask && !([theEvent modifierFlags] & NSControlKeyMask) && @@ -380,11 +384,17 @@ attributedStringInfo getSegments(NSAttributedString *str) - (void) rightMouseDown:(NSEvent *)theEvent { + NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow]; + mMousePos[0] = mPoint.x; + mMousePos[1] = mPoint.y; callRightMouseDown(mMousePos, [theEvent modifierFlags]); } - (void) rightMouseUp:(NSEvent *)theEvent { + NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow]; + mMousePos[0] = mPoint.x; + mMousePos[1] = mPoint.y; callRightMouseUp(mMousePos, [theEvent modifierFlags]); } @@ -431,11 +441,17 @@ attributedStringInfo getSegments(NSAttributedString *str) - (void) otherMouseDown:(NSEvent *)theEvent { + NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow]; + mMousePos[0] = mPoint.x; + mMousePos[1] = mPoint.y; callMiddleMouseDown(mMousePos, [theEvent modifierFlags]); } - (void) otherMouseUp:(NSEvent *)theEvent { + NSPoint mPoint = gHiDPISupport ? [self convertPointToBacking:[theEvent locationInWindow]] : [theEvent locationInWindow]; + mMousePos[0] = mPoint.x; + mMousePos[1] = mPoint.y; callMiddleMouseUp(mMousePos, [theEvent modifierFlags]); } diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h index 34da99de19..10bd3cbb91 100644 --- a/indra/llwindow/llwindowmacosx-objc.h +++ b/indra/llwindow/llwindowmacosx-objc.h @@ -110,9 +110,9 @@ void glSwapBuffers(void* context); CGLContextObj getCGLContextObj(GLViewRef view); unsigned long getVramSize(GLViewRef view); float getDeviceUnitSize(GLViewRef view); -const CGPoint & getContentViewBoundsPosition(NSWindowRef window); -const CGSize & getContentViewBoundsSize(NSWindowRef window); -const CGSize & getDeviceContentViewSize(NSWindowRef window, GLViewRef view); +const CGPoint getContentViewBoundsPosition(NSWindowRef window); +const CGSize getContentViewBoundsSize(NSWindowRef window); +const CGSize getDeviceContentViewSize(NSWindowRef window, GLViewRef view); void getWindowSize(NSWindowRef window, float* size); void setWindowSize(NSWindowRef window, int width, int height); void getCursorPos(NSWindowRef window, float* pos); diff --git a/indra/llwindow/llwindowmacosx-objc.mm b/indra/llwindow/llwindowmacosx-objc.mm index c3eb9b8c8a..8fece7c5c7 100644 --- a/indra/llwindow/llwindowmacosx-objc.mm +++ b/indra/llwindow/llwindowmacosx-objc.mm @@ -258,17 +258,17 @@ float getDeviceUnitSize(GLViewRef view) return [(LLOpenGLView*)view convertSizeToBacking:NSMakeSize(1, 1)].width; } -const CGPoint & getContentViewBoundsPosition(NSWindowRef window) +const CGPoint getContentViewBoundsPosition(NSWindowRef window) { return [[(LLNSWindow*)window contentView] bounds].origin; } -const CGSize & getContentViewBoundsSize(NSWindowRef window) +const CGSize getContentViewBoundsSize(NSWindowRef window) { return [[(LLNSWindow*)window contentView] bounds].size; } -const CGSize & getDeviceContentViewSize(NSWindowRef window, GLViewRef view) +const CGSize getDeviceContentViewSize(NSWindowRef window, GLViewRef view) { return [(NSOpenGLView*)view convertRectToBacking:[[(LLNSWindow*)window contentView] bounds]].size; } diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index fedea3de08..6dec131a34 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -869,10 +869,11 @@ BOOL LLWindowMacOSX::getSize(LLCoordScreen *size) size->mX = sz.width; size->mY = sz.height; + err = noErr; } else { - LL_ERRS() << "LLWindowMacOSX::getPosition(): no window and not fullscreen!" << LL_ENDL; + LL_ERRS() << "LLWindowMacOSX::getSize(): no window and not fullscreen!" << LL_ENDL; } return (err == noErr); @@ -894,10 +895,13 @@ BOOL LLWindowMacOSX::getSize(LLCoordWindow *size) size->mX = sz.width; size->mY = sz.height; + err = noErr; + + } else { - LL_ERRS() << "LLWindowMacOSX::getPosition(): no window and not fullscreen!" << LL_ENDL; + LL_ERRS() << "LLWindowMacOSX::getSize(): no window and not fullscreen!" << LL_ENDL; } return (err == noErr); diff --git a/indra/llxml/llcontrol.cpp b/indra/llxml/llcontrol.cpp index 20ab1a7ad3..ccf4f3ddf5 100644 --- a/indra/llxml/llcontrol.cpp +++ b/indra/llxml/llcontrol.cpp @@ -43,6 +43,9 @@ #include "llrect.h" #include "llxmltree.h" #include "llsdserialize.h" +#include "llfile.h" +#include "lltimer.h" +#include "lldir.h" #if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG #define CONTROL_ERRS LL_ERRS("ControlErrors") @@ -92,6 +95,17 @@ template <> LLSD convert_from_llsd(const LLSD& sd, eControlType type, cons //this defines the current version of the settings file const S32 CURRENT_VERSION = 101; +// If you define the environment variable LL_SETTINGS_PROFILE to any value this will activate +// the gSavedSettings profiling code. This code tracks the calls to get a saved (debug) setting. +// When the viewer exits the results are written to the log directory to the file specified +// by SETTINGS_PROFILE below. Only settings with an average access rate >= 2/second are output. +typedef std::pair settings_pair_t; +typedef std::vector settings_vec_t; +LLSD getCount; +settings_vec_t getCount_v; +F64 start_time = 0; +std::string SETTINGS_PROFILE = "settings_profile.log"; + bool LLControlVariable::llsd_compare(const LLSD& a, const LLSD & b) { bool result = false; @@ -327,6 +341,11 @@ LLSD LLControlVariable::getSaveValue() const LLPointer LLControlGroup::getControl(const std::string& name) { + if (mSettingsProfile) + { + incrCount(name); + } + ctrl_name_table_t::iterator iter = mNameTable.find(name); return iter == mNameTable.end() ? LLPointer() : iter->second; } @@ -349,8 +368,14 @@ const std::string LLControlGroup::mTypeString[TYPE_COUNT] = { "U32" }; LLControlGroup::LLControlGroup(const std::string& name) -: LLInstanceTracker(name) +: LLInstanceTracker(name), + mSettingsProfile(false) { + + if (NULL != getenv("LL_SETTINGS_PROFILE")) + { + mSettingsProfile = true; + } } LLControlGroup::~LLControlGroup() @@ -358,8 +383,66 @@ LLControlGroup::~LLControlGroup() cleanup(); } +static bool compareRoutine(settings_pair_t lhs, settings_pair_t rhs) +{ + return lhs.second > rhs.second; +}; + void LLControlGroup::cleanup() { + if(mSettingsProfile && getCount.size() != 0) + { + std::string file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, SETTINGS_PROFILE); + LLFILE* out = LLFile::fopen(file, "w"); /* Flawfinder: ignore */ + if(!out) + { + LL_WARNS("SettingsProfile") << "Error opening " << SETTINGS_PROFILE << LL_ENDL; + } + else + { + F64 end_time = LLTimer::getTotalSeconds(); + U32 total_seconds = (U32)(end_time - start_time); + + std::string msg = llformat("Runtime (seconds): %d\n\n No. accesses Avg. accesses/sec Name\n", total_seconds); + std::ostringstream data_msg; + + data_msg << msg; + size_t data_size = data_msg.str().size(); + if (fwrite(data_msg.str().c_str(), 1, data_size, out) != data_size) + { + LL_WARNS("SettingsProfile") << "Failed to write settings profile header" << LL_ENDL; + } + + for (LLSD::map_const_iterator iter = getCount.beginMap(); iter != getCount.endMap(); ++iter) + { + getCount_v.push_back(settings_pair_t(iter->first, iter->second.asInteger())); + } + sort(getCount_v.begin(), getCount_v.end(), compareRoutine); + + for (settings_vec_t::iterator iter = getCount_v.begin(); iter != getCount_v.end(); ++iter) + { + U32 access_rate = 0; + if (total_seconds != 0) + { + access_rate = iter->second / total_seconds; + } + if (access_rate >= 2) + { + std::ostringstream data_msg; + msg = llformat("%13d %7d %s", iter->second, access_rate, iter->first.c_str()); + data_msg << msg << "\n"; + size_t data_size = data_msg.str().size(); + if (fwrite(data_msg.str().c_str(), 1, data_size, out) != data_size) + { + LL_WARNS("SettingsProfile") << "Failed to write settings profile" << LL_ENDL; + } + } + } + getCount = LLSD::emptyMap(); + fclose(out); + } + } + mNameTable.clear(); } @@ -460,6 +543,15 @@ LLControlVariable* LLControlGroup::declareLLSD(const std::string& name, const LL return declareControl(name, TYPE_LLSD, initial_val, comment, persist); } +void LLControlGroup::incrCount(const std::string& name) +{ + if (0.0 == start_time) + { + start_time = LLTimer::getTotalSeconds(); + } + getCount[name] = getCount[name].asInteger() + 1; +} + BOOL LLControlGroup::getBOOL(const std::string& name) { return (BOOL)get(name); diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h index 8136a3e88a..de0d366492 100644 --- a/indra/llxml/llcontrol.h +++ b/indra/llxml/llcontrol.h @@ -301,6 +301,9 @@ public: U32 saveToFile(const std::string& filename, BOOL nondefault_only); U32 loadFromFile(const std::string& filename, bool default_values = false, bool save_values = true); void resetToDefaults(); + void incrCount(const std::string& name); + + bool mSettingsProfile; }; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 4dbc6476e0..b36a55d7eb 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -276,6 +276,7 @@ set(viewer_SOURCE_FILES llfloatermemleak.cpp llfloatermodelpreview.cpp llfloatermodeluploadbase.cpp + llfloatermyscripts.cpp llfloaternamedesc.cpp llfloaternotificationsconsole.cpp llfloaternotificationstabbed.cpp @@ -545,6 +546,7 @@ set(viewer_SOURCE_FILES llscrollingpanelparam.cpp llscrollingpanelparambase.cpp llsculptidsize.cpp + llsearchableui.cpp llsearchcombobox.cpp llsearchhistory.cpp llsecapi.cpp @@ -906,6 +908,7 @@ set(viewer_HEADER_FILES llfloatermemleak.h llfloatermodelpreview.h llfloatermodeluploadbase.h + llfloatermyscripts.h llfloaternamedesc.h llfloaternotificationsconsole.h llfloaternotificationstabbed.h @@ -1164,6 +1167,7 @@ set(viewer_HEADER_FILES llscrollingpanelparam.h llscrollingpanelparambase.h llsculptidsize.h + llsearchableui.h llsearchcombobox.h llsearchhistory.h llsecapi.h @@ -1624,6 +1628,7 @@ endif (WINDOWS) # from within the IDE. set(viewer_XUI_FILES skins/default/colors.xml + skins/default/default_languages.xml skins/default/textures/textures.xml ) file(GLOB DEFAULT_XUI_FILE_GLOB_LIST @@ -1878,6 +1883,15 @@ if (WINDOWS) windows-crash-logger ) + # sets the 'working directory' for debugging from visual studio. + # Condition for version can be moved to requirements once build agents will be updated (see TOOL-3865) + if ((NOT UNATTENDED) AND (${CMAKE_VERSION} VERSION_GREATER "3.7.2")) + set_property( + TARGET ${VIEWER_BINARY_NAME} + PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + ) + endif ((NOT UNATTENDED) AND (${CMAKE_VERSION} VERSION_GREATER "3.7.2")) + if (PACKAGE) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/event_host.tar.bz2 @@ -2109,7 +2123,7 @@ if (DARWIN) set(MACOSX_BUNDLE_BUNDLE_NAME "SecondLife") set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}") set(MACOSX_BUNDLE_BUNDLE_VERSION "${VIEWER_SHORT_VERSION}${VIEWER_MACOSX_PHASE}${VIEWER_REVISION}") - set(MACOSX_BUNDLE_COPYRIGHT "Copyright © Linden Research, Inc. 2007") + set(MACOSX_BUNDLE_COPYRIGHT "Copyright © Linden Research, Inc. 2019") set(MACOSX_BUNDLE_NSMAIN_NIB_FILE "SecondLife.nib") set(MACOSX_BUNDLE_NSPRINCIPAL_CLASS "NSApplication") diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index 024b066c0b..ca06394388 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -6.2.1 +6.2.2 diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 7b69ec6eb2..49601ae98f 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -11362,6 +11362,17 @@ Value 0 + MenuSearch + + Comment + Show/hide 'Search menus' field + Persist + 1 + Type + Boolean + Value + 1 + GroupListShowIcons Comment @@ -14090,6 +14101,17 @@ Value 1 + RegionCrossingInterpolationTime + + Comment + How long to extrapolate object motion after crossing regions + Persist + 1 + Type + F32 + Value + 1 + VertexShaderEnable Comment diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi index 4f9a1b7804..d1d5301efe 100644 --- a/indra/newview/installers/windows/installer_template.nsi +++ b/indra/newview/installers/windows/installer_template.nsi @@ -720,9 +720,7 @@ RMDir "$INSTDIR" IfFileExists "$INSTDIR" FOLDERFOUND NOFOLDER FOLDERFOUND: -# Silent uninstall always removes all files (/SD IDYES) - MessageBox MB_YESNO $(DeleteProgramFilesMB) /SD IDYES IDNO NOFOLDER - RMDir /r "$INSTDIR" + MessageBox MB_OK $(DeleteProgramFilesMB) /SD IDOK IDOK NOFOLDER NOFOLDER: diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 1bc21ec469..d6695e7f3e 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -572,12 +572,12 @@ static void settings_to_globals() LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO"); LLImageGL::sGlobalUseAnisotropic = gSavedSettings.getBOOL("RenderAnisotropic"); LLImageGL::sCompressTextures = gSavedSettings.getBOOL("RenderCompressTextures"); - LLVOVolume::sLODFactor = gSavedSettings.getF32("RenderVolumeLODFactor"); + LLVOVolume::sLODFactor = llclamp(gSavedSettings.getF32("RenderVolumeLODFactor"), 0.01f, MAX_LOD_FACTOR); LLVOVolume::sDistanceFactor = 1.f-LLVOVolume::sLODFactor * 0.1f; LLVolumeImplFlexible::sUpdateFactor = gSavedSettings.getF32("RenderFlexTimeFactor"); LLVOTree::sTreeFactor = gSavedSettings.getF32("RenderTreeLODFactor"); - LLVOAvatar::sLODFactor = gSavedSettings.getF32("RenderAvatarLODFactor"); - LLVOAvatar::sPhysicsLODFactor = gSavedSettings.getF32("RenderAvatarPhysicsLODFactor"); + LLVOAvatar::sLODFactor = llclamp(gSavedSettings.getF32("RenderAvatarLODFactor"), 0.f, MAX_AVATAR_LOD_FACTOR); + LLVOAvatar::sPhysicsLODFactor = llclamp(gSavedSettings.getF32("RenderAvatarPhysicsLODFactor"), 0.f, MAX_AVATAR_LOD_FACTOR); LLVOAvatar::updateImpostorRendering(gSavedSettings.getU32("RenderAvatarMaxNonImpostors")); LLVOAvatar::sVisibleInFirstPerson = gSavedSettings.getBOOL("FirstPersonAvatarVisible"); // clamp auto-open time to some minimum usable value @@ -1167,8 +1167,18 @@ bool LLAppViewer::init() // ForceAddressSize updater.args.add(stringize(gSavedSettings.getU32("ForceAddressSize"))); - // Run the updater. An exception from launching the updater should bother us. +#if LL_WINDOWS && !LL_RELEASE_FOR_DOWNLOAD && !LL_SEND_CRASH_REPORTS + // This is neither a release package, nor crash-reporting enabled test build + // try to run version updater, but don't bother if it fails (file might be missing) + LLLeap *leap_p = LLLeap::create(updater, false); + if (!leap_p) + { + LL_WARNS("LLLeap") << "Failed to run LLLeap" << LL_ENDL; + } +#else + // Run the updater. An exception from launching the updater should bother us. LLLeap::create(updater, true); +#endif // Iterate over --leap command-line options. But this is a bit tricky: if // there's only one, it won't be an array at all. @@ -2168,7 +2178,7 @@ bool LLAppViewer::initThreads() if (LLTrace::BlockTimer::sLog || LLTrace::BlockTimer::sMetricLog) { - LLTrace::BlockTimer::setLogLock(new LLMutex(NULL)); + LLTrace::BlockTimer::setLogLock(new LLMutex()); mFastTimerLogThread = new LLFastTimerLogThread(LLTrace::BlockTimer::sLogName); mFastTimerLogThread->start(); } @@ -5462,7 +5472,8 @@ void LLAppViewer::resumeMainloopTimeout(const std::string& state, F32 secs) { if(secs < 0.0f) { - secs = gSavedSettings.getF32("MainloopTimeoutDefault"); + static LLCachedControl mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60); + secs = mainloop_timeout; } mMainloopTimeout->setTimeout(secs); @@ -5489,7 +5500,8 @@ void LLAppViewer::pingMainloopTimeout(const std::string& state, F32 secs) { if(secs < 0.0f) { - secs = gSavedSettings.getF32("MainloopTimeoutDefault"); + static LLCachedControl mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60); + secs = mainloop_timeout; } mMainloopTimeout->setTimeout(secs); diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index e607b4a994..788fe6a19b 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -43,6 +43,7 @@ #define LL_LLAPPVIEWER_H #include "llallocator.h" +#include "llapr.h" #include "llcontrol.h" #include "llsys.h" // for LLOSInfo #include "lltimer.h" diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp index 81f04744f8..3111540a13 100644 --- a/indra/newview/llappviewermacosx.cpp +++ b/indra/newview/llappviewermacosx.cpp @@ -411,68 +411,6 @@ std::string LLAppViewerMacOSX::generateSerialNumber() return serial_md5; } -static AudioDeviceID get_default_audio_output_device(void) -{ - AudioDeviceID device = 0; - UInt32 size = sizeof(device); - AudioObjectPropertyAddress device_address = { kAudioHardwarePropertyDefaultOutputDevice, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster }; - - OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &device_address, 0, NULL, &size, &device); - if(err != noErr) - { - LL_DEBUGS("SystemMute") << "Couldn't get default audio output device (0x" << std::hex << err << ")" << LL_ENDL; - } - - return device; -} - -//virtual -void LLAppViewerMacOSX::setMasterSystemAudioMute(bool new_mute) -{ - AudioDeviceID device = get_default_audio_output_device(); - - if(device != 0) - { - UInt32 mute = new_mute; - AudioObjectPropertyAddress device_address = { kAudioDevicePropertyMute, - kAudioDevicePropertyScopeOutput, - kAudioObjectPropertyElementMaster }; - - OSStatus err = AudioObjectSetPropertyData(device, &device_address, 0, NULL, sizeof(mute), &mute); - if(err != noErr) - { - LL_INFOS("SystemMute") << "Couldn't set audio mute property (0x" << std::hex << err << ")" << LL_ENDL; - } - } -} - -//virtual -bool LLAppViewerMacOSX::getMasterSystemAudioMute() -{ - // Assume the system isn't muted - UInt32 mute = 0; - - AudioDeviceID device = get_default_audio_output_device(); - - if(device != 0) - { - UInt32 size = sizeof(mute); - AudioObjectPropertyAddress device_address = { kAudioDevicePropertyMute, - kAudioDevicePropertyScopeOutput, - kAudioObjectPropertyElementMaster }; - - OSStatus err = AudioObjectGetPropertyData(device, &device_address, 0, NULL, &size, &mute); - if(err != noErr) - { - LL_DEBUGS("SystemMute") << "Couldn't get audio mute property (0x" << std::hex << err << ")" << LL_ENDL; - } - } - - return (mute != 0); -} - void handleUrl(const char* url_utf8) { if (url_utf8 && gViewerAppPtr) diff --git a/indra/newview/llappviewermacosx.h b/indra/newview/llappviewermacosx.h index ebb41a495c..d5a80864be 100644 --- a/indra/newview/llappviewermacosx.h +++ b/indra/newview/llappviewermacosx.h @@ -42,10 +42,6 @@ public: // virtual bool init(); // Override to do application initialization - // mute/unmute the system's master audio - virtual void setMasterSystemAudioMute(bool mute); - virtual bool getMasterSystemAudioMute(); - protected: virtual bool restoreErrorTrap(); virtual void initCrashReporting(bool reportFreeze); diff --git a/indra/newview/llautoreplace.cpp b/indra/newview/llautoreplace.cpp index dd9354fe3a..0516520c56 100644 --- a/indra/newview/llautoreplace.cpp +++ b/indra/newview/llautoreplace.cpp @@ -68,8 +68,8 @@ void LLAutoReplace::autoreplaceCallback(S32& replacement_start, S32& replacement word_start--; // walk word_start back to the beginning of the word } LL_DEBUGS("AutoReplace") << "word_start: " << word_start << " word_end: " << word_end << LL_ENDL; - std::string str_text = std::string(input_text.begin(), input_text.end()); - std::string last_word = str_text.substr(word_start, word_end - word_start + 1); + LLWString old_string = input_text.substr(word_start, word_end - word_start + 1); + std::string last_word = wstring_to_utf8str(old_string); std::string replacement_word(mSettings.replaceWord(last_word)); if (replacement_word != last_word) @@ -79,9 +79,8 @@ void LLAutoReplace::autoreplaceCallback(S32& replacement_start, S32& replacement { // return the replacement string replacement_start = word_start; - replacement_length = last_word.length(); + replacement_length = word_end - word_start + 1; replacement_string = utf8str_to_wstring(replacement_word); - LLWString old_string = utf8str_to_wstring(last_word); S32 size_change = replacement_string.size() - old_string.size(); cursor_pos += size_change; } diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp index af3fac91bc..396b69ae3a 100644 --- a/indra/newview/llavatarlistitem.cpp +++ b/indra/newview/llavatarlistitem.cpp @@ -119,6 +119,7 @@ BOOL LLAvatarListItem::postBuild() mIconPermissionEditTheirs->setVisible(false); mSpeakingIndicator = getChild("speaking_indicator"); + mSpeakingIndicator->setChannelState(LLOutputMonitorCtrl::UNDEFINED_CHANNEL); mInfoBtn = getChild("info_btn"); mProfileBtn = getChild("profile_btn"); diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp index eddc87efcd..4f42868f1a 100644 --- a/indra/newview/llchatitemscontainerctrl.cpp +++ b/indra/newview/llchatitemscontainerctrl.cpp @@ -29,6 +29,7 @@ #include "llchatitemscontainerctrl.h" #include "lltextbox.h" +#include "llavataractions.h" #include "llavatariconctrl.h" #include "llcommandhandler.h" #include "llfloaterreg.h" @@ -204,6 +205,7 @@ void LLFloaterIMNearbyChatToastPanel::init(LLSD& notification) mMsgText = getChild("msg_text", false); mMsgText->setContentTrusted(false); + mMsgText->setIsFriendCallback(LLAvatarActions::isFriend); mMsgText->setText(std::string("")); diff --git a/indra/newview/llcofwearables.cpp b/indra/newview/llcofwearables.cpp index 307f93e28c..b47e0930a3 100644 --- a/indra/newview/llcofwearables.cpp +++ b/indra/newview/llcofwearables.cpp @@ -42,6 +42,7 @@ #include "llwearableitemslist.h" #include "llpaneloutfitedit.h" #include "lltrans.h" +#include "llvoavatarself.h" static LLPanelInjector t_cof_wearables("cof_wearables"); @@ -330,7 +331,7 @@ void LLCOFWearables::setAttachmentsTitle() { if (mAttachmentsTab) { - U32 free_slots = MAX_AGENT_ATTACHMENTS - mAttachments->size(); + U32 free_slots = gAgentAvatarp->getMaxAttachments() - mAttachments->size(); LLStringUtil::format_map_t args_attachments; args_attachments["[COUNT]"] = llformat ("%d", free_slots); diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp index ebbbf23dee..c258136889 100644 --- a/indra/newview/llconversationmodel.cpp +++ b/indra/newview/llconversationmodel.cpp @@ -351,7 +351,7 @@ void LLConversationItemSession::setParticipantIsMuted(const LLUUID& participant_ LLConversationItemParticipant* participant = findParticipant(participant_id); if (participant) { - participant->muteVoice(is_muted); + participant->moderateVoice(is_muted); } } @@ -498,6 +498,7 @@ void LLConversationItemSession::onAvatarNameCache(const LLAvatarName& av_name) LLConversationItemParticipant::LLConversationItemParticipant(std::string display_name, const LLUUID& uuid, LLFolderViewModelInterface& root_view_model) : LLConversationItem(display_name,uuid,root_view_model), + mIsModeratorMuted(false), mIsModerator(false), mDisplayModeratorLabel(false), mDistToAgent(-1.0) @@ -508,6 +509,7 @@ LLConversationItemParticipant::LLConversationItemParticipant(std::string display LLConversationItemParticipant::LLConversationItemParticipant(const LLUUID& uuid, LLFolderViewModelInterface& root_view_model) : LLConversationItem(uuid,root_view_model), + mIsModeratorMuted(false), mIsModerator(false), mDisplayModeratorLabel(false), mDistToAgent(-1.0) @@ -597,25 +599,7 @@ void LLConversationItemParticipant::setDisplayModeratorRole(bool displayRole) bool LLConversationItemParticipant::isVoiceMuted() { - return LLMuteList::getInstance()->isMuted(mUUID, LLMute::flagVoiceChat); -} - -void LLConversationItemParticipant::muteVoice(bool mute_voice) -{ - LLAvatarName av_name; - LLAvatarNameCache::get(mUUID, &av_name); - LLMuteList * mute_listp = LLMuteList::getInstance(); - bool voice_already_muted = mute_listp->isMuted(mUUID, av_name.getUserName()); - - LLMute mute(mUUID, av_name.getUserName(), LLMute::AGENT); - if (voice_already_muted && !mute_voice) - { - mute_listp->remove(mute); - } - else if (!voice_already_muted && mute_voice) - { - mute_listp->add(mute); - } + return mIsModeratorMuted || LLMuteList::getInstance()->isMuted(mUUID, LLMute::flagVoiceChat); } // diff --git a/indra/newview/llconversationmodel.h b/indra/newview/llconversationmodel.h index 3868bafae4..80385fad5f 100644 --- a/indra/newview/llconversationmodel.h +++ b/indra/newview/llconversationmodel.h @@ -194,8 +194,9 @@ public: virtual const std::string& getDisplayName() const { return mDisplayName; } bool isVoiceMuted(); + bool isModeratorMuted() { return mIsModeratorMuted; } bool isModerator() const { return mIsModerator; } - void muteVoice(bool mute_voice); + void moderateVoice(bool mute_voice) { mIsModeratorMuted = mute_voice; } void setIsModerator(bool is_moderator) { mIsModerator = is_moderator; mNeedsRefresh = true; } void setTimeNow() { mLastActiveTime = LLFrameTimer::getElapsedSeconds(); mNeedsRefresh = true; } void setDistance(F64 dist) { mDistToAgent = dist; mNeedsRefresh = true; } @@ -216,6 +217,7 @@ private: void onAvatarNameCache(const LLAvatarName& av_name); // callback used by fetchAvatarName void updateName(const LLAvatarName& av_name); + bool mIsModeratorMuted; // default is false bool mIsModerator; // default is false bool mDisplayModeratorLabel; // default is false std::string mDisplayName; diff --git a/indra/newview/llconversationview.cpp b/indra/newview/llconversationview.cpp index 15a8aacd37..0075b62100 100644 --- a/indra/newview/llconversationview.cpp +++ b/indra/newview/llconversationview.cpp @@ -234,6 +234,8 @@ void LLConversationViewSession::draw() // Draw children if root folder, or any other folder that is open. Do not draw children when animating to closed state or you get rendering overlap. bool draw_children = getRoot() == static_cast(this) || isOpen(); + // Todo/fix this: arrange hides children 'out of bonds', session 'slowly' adjusts container size, unhides children + // this process repeats until children fit for (folders_t::iterator iter = mFolders.begin(); iter != mFolders.end();) { @@ -254,9 +256,6 @@ void LLConversationViewSession::draw() updateLabelRotation(); drawOpenFolderArrow(default_params, sFgColor); } - - refresh(); - LLView::draw(); } @@ -441,28 +440,23 @@ void LLConversationViewSession::refresh() LLSpeakingIndicatorManager::updateSpeakingIndicators(); // we should show indicator for specified voice session only if this is current channel. EXT-5562. - if (!mIsInActiveVoiceChannel) + if (mSpeakingIndicator) { - if (mSpeakingIndicator) + mSpeakingIndicator->setIsActiveChannel(mIsInActiveVoiceChannel); + mSpeakingIndicator->setShowParticipantsSpeaking(mIsInActiveVoiceChannel); + } + + LLConversationViewParticipant* participant = NULL; + items_t::const_iterator iter; + for (iter = getItemsBegin(); iter != getItemsEnd(); iter++) + { + participant = dynamic_cast(*iter); + if (participant) { - mSpeakingIndicator->setVisible(false); - } - LLConversationViewParticipant* participant = NULL; - items_t::const_iterator iter; - for (iter = getItemsBegin(); iter != getItemsEnd(); iter++) - { - participant = dynamic_cast(*iter); - if (participant) - { - participant->hideSpeakingIndicator(); - } + participant->allowSpeakingIndicator(mIsInActiveVoiceChannel); } } - - if (mSpeakingIndicator) - { - mSpeakingIndicator->setShowParticipantsSpeaking(mIsInActiveVoiceChannel); - } + requestArrange(); // Do the regular upstream refresh LLFolderViewFolder::refresh(); @@ -474,8 +468,13 @@ void LLConversationViewSession::onCurrentVoiceSessionChanged(const LLUUID& sessi if (vmi) { + bool old_value = mIsInActiveVoiceChannel; mIsInActiveVoiceChannel = vmi->getUUID() == session_id; mCallIconLayoutPanel->setVisible(mIsInActiveVoiceChannel); + if (old_value != mIsInActiveVoiceChannel) + { + refresh(); + } } } @@ -568,6 +567,7 @@ void LLConversationViewParticipant::draw() F32 text_left = (F32)getLabelXPos(); LLColor4 color; + LLLocalSpeakerMgr *speakerMgr = LLLocalSpeakerMgr::getInstance(); if (speakerMgr && speakerMgr->isSpeakerToBeRemoved(mUUID)) @@ -579,9 +579,14 @@ void LLConversationViewParticipant::draw() color = mIsSelected ? sHighlightFgColor : sFgColor; } + LLConversationItemParticipant* participant_model = dynamic_cast(getViewModelItem()); + if (participant_model) + { + mSpeakingIndicator->setIsModeratorMuted(participant_model->isModeratorMuted()); + } + drawHighlight(show_context, mIsSelected, sHighlightBgColor, sFlashBgColor, sFocusOutlineColor, sMouseOverColor); drawLabel(font, text_left, y, color, right_x); - refresh(); LLView::draw(); } @@ -605,16 +610,39 @@ S32 LLConversationViewParticipant::arrange(S32* width, S32* height) return arranged; } +// virtual +void LLConversationViewParticipant::refresh() +{ + // Refresh the participant view from its model data + LLConversationItemParticipant* participant_model = dynamic_cast(getViewModelItem()); + participant_model->resetRefresh(); + + // *TODO: We should also do something with vmi->isModerator() to echo that state in the UI somewhat + mSpeakingIndicator->setIsModeratorMuted(participant_model->isModeratorMuted()); + + // Do the regular upstream refresh + LLFolderViewItem::refresh(); +} + void LLConversationViewParticipant::addToFolder(LLFolderViewFolder* folder) { // Add the item to the folder (conversation) LLFolderViewItem::addToFolder(folder); // Retrieve the folder (conversation) UUID, which is also the speaker session UUID - LLConversationItem* vmi = getParentFolder() ? dynamic_cast(getParentFolder()->getViewModelItem()) : NULL; - if (vmi) + LLFolderViewFolder *prnt = getParentFolder(); + if (prnt) { - addToSession(vmi->getUUID()); + LLConversationItem* vmi = dynamic_cast(prnt->getViewModelItem()); + if (vmi) + { + addToSession(vmi->getUUID()); + } + LLConversationViewSession* session = dynamic_cast(prnt); + if (session) + { + allowSpeakingIndicator(session->isInActiveVoiceChannel()); + } } } @@ -744,9 +772,9 @@ LLView* LLConversationViewParticipant::getItemChildView(EAvatarListItemChildInde return child_view; } -void LLConversationViewParticipant::hideSpeakingIndicator() +void LLConversationViewParticipant::allowSpeakingIndicator(bool val) { - mSpeakingIndicator->setVisible(false); + mSpeakingIndicator->setIsActiveChannel(val); } // EOF diff --git a/indra/newview/llconversationview.h b/indra/newview/llconversationview.h index 5a74974302..420c250dfe 100644 --- a/indra/newview/llconversationview.h +++ b/indra/newview/llconversationview.h @@ -90,6 +90,7 @@ public: void setHighlightState(bool hihglight_state); LLFloater* getSessionFloater(); + bool isInActiveVoiceChannel() { return mIsInActiveVoiceChannel; } private: @@ -136,6 +137,7 @@ public: virtual ~LLConversationViewParticipant( void ); bool hasSameValue(const LLUUID& uuid) { return (uuid == mUUID); } + /*virtual*/ void refresh(); void addToFolder(LLFolderViewFolder* folder); void addToSession(const LLUUID& session_id); @@ -144,7 +146,7 @@ public: /*virtual*/ S32 getLabelXPos(); /*virtual*/ BOOL handleMouseDown( S32 x, S32 y, MASK mask ); - void hideSpeakingIndicator(); + void allowSpeakingIndicator(bool val); protected: friend class LLUICtrlFactory; diff --git a/indra/newview/lldirpicker.cpp b/indra/newview/lldirpicker.cpp index 5443afe60c..b8e6e81ee6 100644 --- a/indra/newview/lldirpicker.cpp +++ b/indra/newview/lldirpicker.cpp @@ -315,7 +315,7 @@ void LLDirPickerThread::run() //static void LLDirPickerThread::initClass() { - sMutex = new LLMutex(NULL); + sMutex = new LLMutex(); } //static diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 0f22b6200f..b6fd70452e 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -101,6 +101,8 @@ LLFilePicker::LLFilePicker() mOFN.lpfnHook = NULL; mOFN.lpTemplateName = NULL; mFilesW[0] = '\0'; +#elif LL_DARWIN + mPickOptions = 0; #endif } diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index c5561fe011..33099db1b9 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -812,7 +812,7 @@ bool LLFloaterAvatarPicker::isSelectBtnEnabled() { bool ret_val = visibleItemsSelected(); - if ( ret_val ) + if ( ret_val && !isMinimized()) { std::string acvtive_panel_name; LLScrollListCtrl* list = NULL; diff --git a/indra/newview/llfloaterconversationpreview.cpp b/indra/newview/llfloaterconversationpreview.cpp index b48ecc8f31..66198b3bf6 100644 --- a/indra/newview/llfloaterconversationpreview.cpp +++ b/indra/newview/llfloaterconversationpreview.cpp @@ -46,7 +46,7 @@ LLFloaterConversationPreview::LLFloaterConversationPreview(const LLSD& session_i mPageSize(gSavedSettings.getS32("ConversationHistoryPageSize")), mAccountName(session_id[LL_FCP_ACCOUNT_NAME]), mCompleteName(session_id[LL_FCP_COMPLETE_NAME]), - mMutex(NULL), + mMutex(), mShowHistory(false), mMessages(NULL), mHistoryThreadsBusy(false), diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index 3cfa1133df..30d05ae287 100644 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -269,6 +269,9 @@ BOOL LLFloaterIMContainer::postBuild() // When display name option change, we need to reload all participant names LLAvatarNameCache::addUseDisplayNamesCallback(boost::bind(&LLFloaterIMContainer::processParticipantsStyleUpdate, this)); + mParticipantRefreshTimer.setTimerExpirySec(0); + mParticipantRefreshTimer.start(); + return TRUE; } @@ -420,14 +423,66 @@ void LLFloaterIMContainer::processParticipantsStyleUpdate() void LLFloaterIMContainer::idle(void* user_data) { LLFloaterIMContainer* self = static_cast(user_data); - - // Update the distance to agent in the nearby chat session if required - // Note: it makes no sense of course to update the distance in other session - if (self->mConversationViewModel.getSorter().getSortOrderParticipants() == LLConversationFilter::SO_DISTANCE) - { - self->setNearbyDistances(); - } - self->mConversationsRoot->update(); + + if (!self->getVisible() || self->isMinimized()) + { + return; + } + self->idleUpdate(); +} + +void LLFloaterIMContainer::idleUpdate() +{ + if (mTabContainer->getTabCount() == 0) + { + // Do not close the container when every conversation is torn off because the user + // still needs the conversation list. Simply collapse the message pane in that case. + collapseMessagesPane(true); + } + + U32 sort_order = mConversationViewModel.getSorter().getSortOrderParticipants(); + + if (mParticipantRefreshTimer.hasExpired()) + { + const LLConversationItem *current_session = getCurSelectedViewModelItem(); + if (current_session) + { + // Update moderator options visibility + LLFolderViewModelItemCommon::child_list_t::const_iterator current_participant_model = current_session->getChildrenBegin(); + LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = current_session->getChildrenEnd(); + bool is_moderator = isGroupModerator(); + bool can_ban = haveAbilityToBan(); + while (current_participant_model != end_participant_model) + { + LLConversationItemParticipant* participant_model = dynamic_cast(*current_participant_model); + participant_model->setModeratorOptionsVisible(is_moderator && participant_model->getUUID() != gAgentID); + participant_model->setGroupBanVisible(can_ban && participant_model->getUUID() != gAgentID); + + current_participant_model++; + } + // Update floater's title as required by the currently selected session or use the default title + LLFloaterIMSession * conversation_floaterp = LLFloaterIMSession::findInstance(current_session->getUUID()); + setTitle(conversation_floaterp && conversation_floaterp->needsTitleOverwrite() ? conversation_floaterp->getTitle() : mGeneralTitle); + } + + mParticipantRefreshTimer.setTimerExpirySec(1.0f); + } + + // Update the distance to agent in the nearby chat session if required + // Note: it makes no sense of course to update the distance in other session + if (sort_order == LLConversationFilter::SO_DISTANCE) + { + // almost real-time updates + setNearbyDistances(); //calls arrange all + } + mConversationsRoot->update(); //arranges, resizes, heavy + + // "Manually" resize of mConversationsPane: same as temporarity cancellation of the flag "auto_resize=false" for it + if (!mConversationsPane->isCollapsed() && mMessagesPane->isCollapsed()) + { + LLRect stack_rect = mConversationsStack->getRect(); + mConversationsPane->reshape(stack_rect.getWidth(), stack_rect.getHeight(), true); + } } bool LLFloaterIMContainer::onConversationModelEvent(const LLSD& event) @@ -526,39 +581,6 @@ bool LLFloaterIMContainer::onConversationModelEvent(const LLSD& event) void LLFloaterIMContainer::draw() { - if (mTabContainer->getTabCount() == 0) - { - // Do not close the container when every conversation is torn off because the user - // still needs the conversation list. Simply collapse the message pane in that case. - collapseMessagesPane(true); - } - - const LLConversationItem *current_session = getCurSelectedViewModelItem(); - if (current_session) - { - // Update moderator options visibility - LLFolderViewModelItemCommon::child_list_t::const_iterator current_participant_model = current_session->getChildrenBegin(); - LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = current_session->getChildrenEnd(); - while (current_participant_model != end_participant_model) - { - LLConversationItemParticipant* participant_model = dynamic_cast(*current_participant_model); - participant_model->setModeratorOptionsVisible(isGroupModerator() && participant_model->getUUID() != gAgentID); - participant_model->setGroupBanVisible(haveAbilityToBan() && participant_model->getUUID() != gAgentID); - - current_participant_model++; - } - // Update floater's title as required by the currently selected session or use the default title - LLFloaterIMSession * conversation_floaterp = LLFloaterIMSession::findInstance(current_session->getUUID()); - setTitle(conversation_floaterp && conversation_floaterp->needsTitleOverwrite() ? conversation_floaterp->getTitle() : mGeneralTitle); - } - - // "Manually" resize of mConversationsPane: same as temporarity cancellation of the flag "auto_resize=false" for it - if (!mConversationsPane->isCollapsed() && mMessagesPane->isCollapsed()) - { - LLRect stack_rect = mConversationsStack->getRect(); - mConversationsPane->reshape(stack_rect.getWidth(), stack_rect.getHeight(), true); - } - LLFloater::draw(); } diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h index 90fc0c2bdd..78b3572111 100644 --- a/indra/newview/llfloaterimcontainer.h +++ b/indra/newview/llfloaterimcontainer.h @@ -180,6 +180,8 @@ private: void openNearbyChat(); bool isParticipantListExpanded(); + void idleUpdate(); // for convenience (self) from static idle + LLButton* mExpandCollapseBtn; LLButton* mStubCollapseBtn; LLButton* mSpeakBtn; @@ -226,6 +228,8 @@ private: LLConversationViewModel mConversationViewModel; LLFolderView* mConversationsRoot; LLEventStream mConversationsEventStream; + + LLTimer mParticipantRefreshTimer; }; #endif // LL_LLFLOATERIMCONTAINER_H diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index 5d97eebd9d..7f2e8fd82a 100644 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -416,6 +416,7 @@ BOOL LLPanelLandGeneral::postBuild() mTextSalePending = getChild("SalePending"); mTextOwnerLabel = getChild("Owner:"); mTextOwner = getChild("OwnerText"); + mTextOwner->setIsFriendCallback(LLAvatarActions::isFriend); mContentRating = getChild("ContentRatingText"); mLandType = getChild("LandTypeText"); @@ -1192,6 +1193,7 @@ BOOL LLPanelLandObjects::postBuild() mIconGroup = LLUIImageList::getInstance()->getUIImage("icon_group.tga", 0); mOwnerList = getChild("owner list"); + mOwnerList->setIsFriendCallback(LLAvatarActions::isFriend); mOwnerList->sortByColumnIndex(3, FALSE); childSetCommitCallback("owner list", onCommitList, this); mOwnerList->setDoubleClickCallback(onDoubleClickOwner, this); diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 268c646719..4f1ea4a89e 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -266,7 +266,7 @@ mCalculateBtn(NULL) sInstance = this; mLastMouseX = 0; mLastMouseY = 0; - mStatusLock = new LLMutex(NULL); + mStatusLock = new LLMutex(); mModelPreview = NULL; mLODMode[LLModel::LOD_HIGH] = 0; @@ -1208,7 +1208,7 @@ void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handl //----------------------------------------------------------------------------- LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) -: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex(NULL) +: LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE), LLMutex() , mLodsQuery() , mLodsWithParsingError() , mPelvisZOffset( 0.0f ) @@ -1418,8 +1418,6 @@ void LLModelPreview::rebuildUploadData() std::string requested_name = mFMP->getChild("description_form")->getValue().asString(); - std::string metric = mFMP->getChild("model_category_combo")->getValue().asString(); - LLSpinCtrl* scale_spinner = mFMP->getChild("import_scale"); F32 scale = scale_spinner->getValue().asReal(); @@ -1460,7 +1458,6 @@ void LLModelPreview::rebuildUploadData() if (base_model && !requested_name.empty()) { base_model->mRequestedLabel = requested_name; - base_model->mMetric = metric; } for (int i = LLModel::NUM_LODS - 1; i >= LLModel::LOD_IMPOSTOR; i--) diff --git a/indra/newview/llfloatermyscripts.cpp b/indra/newview/llfloatermyscripts.cpp new file mode 100644 index 0000000000..fa2de21a8f --- /dev/null +++ b/indra/newview/llfloatermyscripts.cpp @@ -0,0 +1,294 @@ +/** + * @file llfloatermyscripts.cpp + * @brief LLFloaterMyScripts class implementation. + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2019, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llfloatermyscripts.h" + +#include "llagent.h" +#include "llcorehttputil.h" +#include "llcoros.h" +#include "lleventcoro.h" +#include "llfloaterreg.h" +#include "llscrolllistctrl.h" +#include "lltrans.h" +#include "llviewerregion.h" + +const S32 SIZE_OF_ONE_KB = 1024; + +LLFloaterMyScripts::LLFloaterMyScripts(const LLSD& seed) + : LLFloater(seed), + mGotAttachmentMemoryUsed(false), + mAttachmentMemoryMax(0), + mAttachmentMemoryUsed(0), + mGotAttachmentURLsUsed(false), + mAttachmentURLsMax(0), + mAttachmentURLsUsed(0) +{ +} + +BOOL LLFloaterMyScripts::postBuild() +{ + childSetAction("refresh_list_btn", onClickRefresh, this); + + std::string msg_waiting = LLTrans::getString("ScriptLimitsRequestWaiting"); + getChild("loading_text")->setValue(LLSD(msg_waiting)); + return requestAttachmentDetails(); +} + +BOOL LLFloaterMyScripts::requestAttachmentDetails() +{ + if (!gAgent.getRegion()) return FALSE; + + LLSD body; + std::string url = gAgent.getRegion()->getCapability("AttachmentResources"); + if (!url.empty()) + { + LLCoros::instance().launch("LLFloaterMyScripts::getAttachmentLimitsCoro", + boost::bind(&LLFloaterMyScripts::getAttachmentLimitsCoro, this, url)); + return TRUE; + } + else + { + return FALSE; + } +} + +void LLFloaterMyScripts::getAttachmentLimitsCoro(std::string url) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getAttachmentLimitsCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS() << "Unable to retrieve attachment limits." << LL_ENDL; + return; + } + + LLFloaterMyScripts* instance = LLFloaterReg::getTypedInstance("my_scripts"); + + if (!instance) + { + LL_WARNS() << "Failed to get LLFloaterMyScripts instance" << LL_ENDL; + return; + } + + instance->getChild("loading_text")->setValue(LLSD(std::string(""))); + + LLButton* btn = instance->getChild("refresh_list_btn"); + if (btn) + { + btn->setEnabled(true); + } + + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + instance->setAttachmentDetails(result); +} + + +void LLFloaterMyScripts::setAttachmentDetails(LLSD content) +{ + LLScrollListCtrl *list = getChild("scripts_list"); + + if(!list) + { + return; + } + + S32 number_attachments = content["attachments"].size(); + + for(int i = 0; i < number_attachments; i++) + { + std::string humanReadableLocation = ""; + if(content["attachments"][i].has("location")) + { + std::string actualLocation = content["attachments"][i]["location"]; + humanReadableLocation = LLTrans::getString(actualLocation.c_str()); + } + + S32 number_objects = content["attachments"][i]["objects"].size(); + for(int j = 0; j < number_objects; j++) + { + LLUUID task_id = content["attachments"][i]["objects"][j]["id"].asUUID(); + S32 size = 0; + if(content["attachments"][i]["objects"][j]["resources"].has("memory")) + { + size = content["attachments"][i]["objects"][j]["resources"]["memory"].asInteger() / SIZE_OF_ONE_KB; + } + S32 urls = 0; + if(content["attachments"][i]["objects"][j]["resources"].has("urls")) + { + urls = content["attachments"][i]["objects"][j]["resources"]["urls"].asInteger(); + } + std::string name = content["attachments"][i]["objects"][j]["name"].asString(); + + LLSD element; + + element["id"] = task_id; + element["columns"][0]["column"] = "size"; + element["columns"][0]["value"] = llformat("%d", size); + element["columns"][0]["font"] = "SANSSERIF"; + element["columns"][0]["halign"] = LLFontGL::RIGHT; + + element["columns"][1]["column"] = "urls"; + element["columns"][1]["value"] = llformat("%d", urls); + element["columns"][1]["font"] = "SANSSERIF"; + element["columns"][1]["halign"] = LLFontGL::RIGHT; + + element["columns"][2]["column"] = "name"; + element["columns"][2]["value"] = name; + element["columns"][2]["font"] = "SANSSERIF"; + + element["columns"][3]["column"] = "location"; + element["columns"][3]["value"] = humanReadableLocation; + element["columns"][3]["font"] = "SANSSERIF"; + + list->addElement(element); + } + } + + setAttachmentSummary(content); + + getChild("loading_text")->setValue(LLSD(std::string(""))); + + LLButton* btn = getChild("refresh_list_btn"); + if(btn) + { + btn->setEnabled(true); + } +} + +void LLFloaterMyScripts::clearList() +{ + LLCtrlListInterface *list = childGetListInterface("scripts_list"); + + if (list) + { + list->operateOnAll(LLCtrlListInterface::OP_DELETE); + } + + std::string msg_waiting = LLTrans::getString("ScriptLimitsRequestWaiting"); + getChild("loading_text")->setValue(LLSD(msg_waiting)); +} + +void LLFloaterMyScripts::setAttachmentSummary(LLSD content) +{ + if(content["summary"]["used"][0]["type"].asString() == std::string("memory")) + { + mAttachmentMemoryUsed = content["summary"]["used"][0]["amount"].asInteger() / SIZE_OF_ONE_KB; + mAttachmentMemoryMax = content["summary"]["available"][0]["amount"].asInteger() / SIZE_OF_ONE_KB; + mGotAttachmentMemoryUsed = true; + } + else if(content["summary"]["used"][1]["type"].asString() == std::string("memory")) + { + mAttachmentMemoryUsed = content["summary"]["used"][1]["amount"].asInteger() / SIZE_OF_ONE_KB; + mAttachmentMemoryMax = content["summary"]["available"][1]["amount"].asInteger() / SIZE_OF_ONE_KB; + mGotAttachmentMemoryUsed = true; + } + else + { + LL_WARNS() << "attachment details don't contain memory summary info" << LL_ENDL; + return; + } + + if(content["summary"]["used"][0]["type"].asString() == std::string("urls")) + { + mAttachmentURLsUsed = content["summary"]["used"][0]["amount"].asInteger(); + mAttachmentURLsMax = content["summary"]["available"][0]["amount"].asInteger(); + mGotAttachmentURLsUsed = true; + } + else if(content["summary"]["used"][1]["type"].asString() == std::string("urls")) + { + mAttachmentURLsUsed = content["summary"]["used"][1]["amount"].asInteger(); + mAttachmentURLsMax = content["summary"]["available"][1]["amount"].asInteger(); + mGotAttachmentURLsUsed = true; + } + else + { + LL_WARNS() << "attachment details don't contain urls summary info" << LL_ENDL; + return; + } + + if((mAttachmentMemoryUsed >= 0) && (mAttachmentMemoryMax >= 0)) + { + LLStringUtil::format_map_t args_attachment_memory; + args_attachment_memory["[COUNT]"] = llformat ("%d", mAttachmentMemoryUsed); + std::string translate_message = "ScriptLimitsMemoryUsedSimple"; + + if (0 < mAttachmentMemoryMax) + { + S32 attachment_memory_available = mAttachmentMemoryMax - mAttachmentMemoryUsed; + + args_attachment_memory["[MAX]"] = llformat ("%d", mAttachmentMemoryMax); + args_attachment_memory["[AVAILABLE]"] = llformat ("%d", attachment_memory_available); + translate_message = "ScriptLimitsMemoryUsed"; + } + + getChild("memory_used")->setValue(LLTrans::getString(translate_message, args_attachment_memory)); + } + + if((mAttachmentURLsUsed >= 0) && (mAttachmentURLsMax >= 0)) + { + S32 attachment_urls_available = mAttachmentURLsMax - mAttachmentURLsUsed; + + LLStringUtil::format_map_t args_attachment_urls; + args_attachment_urls["[COUNT]"] = llformat ("%d", mAttachmentURLsUsed); + args_attachment_urls["[MAX]"] = llformat ("%d", mAttachmentURLsMax); + args_attachment_urls["[AVAILABLE]"] = llformat ("%d", attachment_urls_available); + std::string msg_attachment_urls = LLTrans::getString("ScriptLimitsURLsUsed", args_attachment_urls); + getChild("urls_used")->setValue(LLSD(msg_attachment_urls)); + } +} + +// static +void LLFloaterMyScripts::onClickRefresh(void* userdata) +{ + LLFloaterMyScripts* instance = LLFloaterReg::getTypedInstance("my_scripts"); + if(instance) + { + LLButton* btn = instance->getChild("refresh_list_btn"); + + //To stop people from hammering the refesh button and accidentally dosing themselves - enough requests can crash the viewer! + //turn the button off, then turn it on when we get a response + if(btn) + { + btn->setEnabled(false); + } + instance->clearList(); + instance->requestAttachmentDetails(); + } + else + { + LL_WARNS() << "could not find LLFloaterMyScripts instance after refresh button clicked" << LL_ENDL; + } +} + diff --git a/indra/newview/llfloatermyscripts.h b/indra/newview/llfloatermyscripts.h new file mode 100644 index 0000000000..fe33ab90ae --- /dev/null +++ b/indra/newview/llfloatermyscripts.h @@ -0,0 +1,60 @@ +/** + * @file llfloatermyscripts.h + * @brief LLFloaterMyScripts class definition. + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2019, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATERMYSCRIPTS_H +#define LL_LLFLOATERMYSCRIPTS_H + +#include "llfloater.h" +#include "llpanel.h" + +class LLFloaterMyScripts : public LLFloater +{ +public: + LLFloaterMyScripts(const LLSD& seed); + + BOOL postBuild(); + void setAttachmentDetails(LLSD content); + void setAttachmentSummary(LLSD content); + BOOL requestAttachmentDetails(); + void clearList(); + +private: + void getAttachmentLimitsCoro(std::string url); + + bool mGotAttachmentMemoryUsed; + S32 mAttachmentMemoryMax; + S32 mAttachmentMemoryUsed; + + bool mGotAttachmentURLsUsed; + S32 mAttachmentURLsMax; + S32 mAttachmentURLsUsed; + +protected: + + static void onClickRefresh(void* userdata); +}; + +#endif diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index b89de6a310..927124f333 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -117,6 +117,8 @@ #include "llfeaturemanager.h" #include "llviewertexturelist.h" +#include "llsearchableui.h" + const F32 BANDWIDTH_UPDATER_TIMEOUT = 0.5f; char const* const VISIBILITY_DEFAULT = "default"; char const* const VISIBILITY_HIDDEN = "hidden"; @@ -136,6 +138,25 @@ static const F32 MIN_ARC_LOG = log(MIN_ARC_LIMIT); static const F32 MAX_ARC_LOG = log(MAX_ARC_LIMIT); static const F32 ARC_LIMIT_MAP_SCALE = (MAX_ARC_LOG - MIN_ARC_LOG) / (MAX_INDIRECT_ARC_LIMIT - MIN_INDIRECT_ARC_LIMIT); +struct LabelDef : public LLInitParam::Block +{ + Mandatory name; + Mandatory value; + + LabelDef() + : name("name"), + value("value") + {} +}; + +struct LabelTable : public LLInitParam::Block +{ + Multiple labels; + LabelTable() + : labels("label") + {} +}; + class LLVoiceSetKeyDialog : public LLModalDialog { public: @@ -393,6 +414,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mCommitCallbackRegistrar.add("Pref.ClearLog", boost::bind(&LLConversationLog::onClearLog, &LLConversationLog::instance())); mCommitCallbackRegistrar.add("Pref.DeleteTranscripts", boost::bind(&LLFloaterPreference::onDeleteTranscripts, this)); + mCommitCallbackRegistrar.add("UpdateFilter", boost::bind(&LLFloaterPreference::onUpdateFilterTerm, this, false)); // Hook up for filtering } void LLFloaterPreference::processProperties( void* pData, EAvatarProcessorType type ) @@ -506,7 +528,33 @@ BOOL LLFloaterPreference::postBuild() LLSliderCtrl* fov_slider = getChild("camera_fov"); fov_slider->setMinValue(LLViewerCamera::getInstance()->getMinView()); fov_slider->setMaxValue(LLViewerCamera::getInstance()->getMaxView()); + + // Hook up and init for filtering + mFilterEdit = getChild("search_prefs_edit"); + mFilterEdit->setKeystrokeCallback(boost::bind(&LLFloaterPreference::onUpdateFilterTerm, this, false)); + // Load and assign label for 'default language' + std::string user_filename = gDirUtilp->getExpandedFilename(LL_PATH_DEFAULT_SKIN, "default_languages.xml"); + std::map labels; + if (loadFromFilename(user_filename, labels)) + { + std::string system_lang = gSavedSettings.getString("SystemLanguage"); + std::map::iterator iter = labels.find(system_lang); + if (iter != labels.end()) + { + getChild("language_combobox")->add(iter->second, LLSD("default"), ADD_TOP, true); + } + else + { + LL_WARNS() << "Language \"" << system_lang << "\" is not in default_languages.xml" << LL_ENDL; + getChild("language_combobox")->add("System default", LLSD("default"), ADD_TOP, true); + } + } + else + { + LL_WARNS() << "Failed to load labels from " << user_filename << ". Using default." << LL_ENDL; + getChild("language_combobox")->add("System default", LLSD("default"), ADD_TOP, true); + } return TRUE; } @@ -2349,6 +2397,7 @@ BOOL LLPanelPreference::postBuild() if (hasChild("mute_chb_label", TRUE)) { getChild("mute_chb_label")->setShowCursorHand(false); + getChild("mute_chb_label")->setSoundFlags(LLView::MOUSE_UP); getChild("mute_chb_label")->setClickedCallback(boost::bind(&toggleMuteWhenMinimized)); } @@ -2472,6 +2521,11 @@ void LLPanelPreference::toggleMuteWhenMinimized() { std::string mute("MuteWhenMinimized"); gSavedSettings.setBOOL(mute, !gSavedSettings.getBOOL(mute)); + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); + if (instance) + { + instance->getChild("mute_when_minimized")->setBtnFocus(); + } } void LLPanelPreference::cancel() @@ -3079,3 +3133,109 @@ void LLFloaterPreferenceProxy::onChangeSocksSettings() } +void LLFloaterPreference::onUpdateFilterTerm(bool force) +{ + LLWString seachValue = utf8str_to_wstring( mFilterEdit->getValue() ); + LLWStringUtil::toLower( seachValue ); + + if( !mSearchData || (mSearchData->mLastFilter == seachValue && !force)) + return; + + mSearchData->mLastFilter = seachValue; + + if( !mSearchData->mRootTab ) + return; + + mSearchData->mRootTab->hightlightAndHide( seachValue ); + LLTabContainer *pRoot = getChild< LLTabContainer >( "pref core" ); + if( pRoot ) + pRoot->selectFirstTab(); +} + +void collectChildren( LLView const *aView, ll::prefs::PanelDataPtr aParentPanel, ll::prefs::TabContainerDataPtr aParentTabContainer ) +{ + if( !aView ) + return; + + llassert_always( aParentPanel || aParentTabContainer ); + + LLView::child_list_const_iter_t itr = aView->beginChild(); + LLView::child_list_const_iter_t itrEnd = aView->endChild(); + + while( itr != itrEnd ) + { + LLView *pView = *itr; + ll::prefs::PanelDataPtr pCurPanelData = aParentPanel; + ll::prefs::TabContainerDataPtr pCurTabContainer = aParentTabContainer; + if( !pView ) + continue; + LLPanel const *pPanel = dynamic_cast< LLPanel const *>( pView ); + LLTabContainer const *pTabContainer = dynamic_cast< LLTabContainer const *>( pView ); + ll::ui::SearchableControl const *pSCtrl = dynamic_cast< ll::ui::SearchableControl const *>( pView ); + + if( pTabContainer ) + { + pCurPanelData.reset(); + + pCurTabContainer = ll::prefs::TabContainerDataPtr( new ll::prefs::TabContainerData ); + pCurTabContainer->mTabContainer = const_cast< LLTabContainer *>( pTabContainer ); + pCurTabContainer->mLabel = pTabContainer->getLabel(); + pCurTabContainer->mPanel = 0; + + if( aParentPanel ) + aParentPanel->mChildPanel.push_back( pCurTabContainer ); + if( aParentTabContainer ) + aParentTabContainer->mChildPanel.push_back( pCurTabContainer ); + } + else if( pPanel ) + { + pCurTabContainer.reset(); + + pCurPanelData = ll::prefs::PanelDataPtr( new ll::prefs::PanelData ); + pCurPanelData->mPanel = pPanel; + pCurPanelData->mLabel = pPanel->getLabel(); + + llassert_always( aParentPanel || aParentTabContainer ); + + if( aParentTabContainer ) + aParentTabContainer->mChildPanel.push_back( pCurPanelData ); + else if( aParentPanel ) + aParentPanel->mChildPanel.push_back( pCurPanelData ); + } + else if( pSCtrl && pSCtrl->getSearchText().size() ) + { + ll::prefs::SearchableItemPtr item = ll::prefs::SearchableItemPtr( new ll::prefs::SearchableItem() ); + item->mView = pView; + item->mCtrl = pSCtrl; + + item->mLabel = utf8str_to_wstring( pSCtrl->getSearchText() ); + LLWStringUtil::toLower( item->mLabel ); + + llassert_always( aParentPanel || aParentTabContainer ); + + if( aParentPanel ) + aParentPanel->mChildren.push_back( item ); + if( aParentTabContainer ) + aParentTabContainer->mChildren.push_back( item ); + } + collectChildren( pView, pCurPanelData, pCurTabContainer ); + ++itr; + } +} + +void LLFloaterPreference::collectSearchableItems() +{ + mSearchData.reset( nullptr ); + LLTabContainer *pRoot = getChild< LLTabContainer >( "pref core" ); + if( mFilterEdit && pRoot ) + { + mSearchData.reset(new ll::prefs::SearchData() ); + + ll::prefs::TabContainerDataPtr pRootTabcontainer = ll::prefs::TabContainerDataPtr( new ll::prefs::TabContainerData ); + pRootTabcontainer->mTabContainer = pRoot; + pRootTabcontainer->mLabel = pRoot->getLabel(); + mSearchData->mRootTab = pRootTabcontainer; + + collectChildren( this, ll::prefs::PanelDataPtr(), pRootTabcontainer ); + } +} diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index da96e68f5e..54f985193a 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -36,6 +36,7 @@ #include "llfloater.h" #include "llavatarpropertiesprocessor.h" #include "llconversationlog.h" +#include "llsearcheditor.h" class LLConversationLogObserver; class LLPanelPreference; @@ -47,6 +48,14 @@ class LLSliderCtrl; class LLSD; class LLTextBox; +namespace ll +{ + namespace prefs + { + struct SearchData; + } +} + typedef std::map notifications_map; typedef enum @@ -207,6 +216,12 @@ private: std::string mSavedCameraPreset; std::string mSavedGraphicsPreset; LOG_CLASS(LLFloaterPreference); + + LLSearchEditor *mFilterEdit; + std::unique_ptr< ll::prefs::SearchData > mSearchData; + + void onUpdateFilterTerm( bool force = false ); + void collectSearchableItems(); }; class LLPanelPreference : public LLPanel @@ -256,18 +271,6 @@ private: LOG_CLASS(LLPanelPreference); }; -class LLPanelPreferenceView : public LLPanelPreference -{ -public: - BOOL postBuild(); - void draw(); - void setPresetText(); - -private: - void onPresetsListChangeCamera(); - LOG_CLASS(LLPanelPreferenceView); -}; - class LLPanelPreferenceGraphics : public LLPanelPreference { public: @@ -285,6 +288,7 @@ protected: bool hasDirtyChilds(); private: + void onPresetsListChange(); LOG_CLASS(LLPanelPreferenceGraphics); }; diff --git a/indra/newview/llfloaterscriptlimits.cpp b/indra/newview/llfloaterscriptlimits.cpp index 21df769d0c..3746b9b6c2 100644 --- a/indra/newview/llfloaterscriptlimits.cpp +++ b/indra/newview/llfloaterscriptlimits.cpp @@ -90,19 +90,6 @@ LLFloaterScriptLimits::LLFloaterScriptLimits(const LLSD& seed) BOOL LLFloaterScriptLimits::postBuild() { - // a little cheap and cheerful - if there's an about land panel open default to showing parcel info, - // otherwise default to showing attachments (avatar appearance) - bool selectParcelPanel = false; - - LLFloaterLand* instance = LLFloaterReg::getTypedInstance("about_land"); - if(instance) - { - if(instance->isShown()) - { - selectParcelPanel = true; - } - } - mTab = getChild("scriptlimits_panels"); if(!mTab) @@ -111,28 +98,12 @@ BOOL LLFloaterScriptLimits::postBuild() return FALSE; } - // contruct the panels + // contruct the panel LLPanelScriptLimitsRegionMemory* panel_memory = new LLPanelScriptLimitsRegionMemory; mInfoPanels.push_back(panel_memory); panel_memory->buildFromFile( "panel_script_limits_region_memory.xml"); mTab->addTabPanel(panel_memory); - - LLPanelScriptLimitsAttachment* panel_attachments = new LLPanelScriptLimitsAttachment; - mInfoPanels.push_back(panel_attachments); - panel_attachments->buildFromFile("panel_script_limits_my_avatar.xml"); - mTab->addTabPanel(panel_attachments); - - - if(mInfoPanels.size() > 0) - { - mTab->selectTab(0); - } - - if(!selectParcelPanel && (mInfoPanels.size() > 1)) - { - mTab->selectTab(1); - } - + mTab->selectTab(0); return TRUE; } @@ -969,269 +940,3 @@ void LLPanelScriptLimitsRegionMemory::onClickReturn(void* userdata) } } -///---------------------------------------------------------------------------- -// Attachment Panel -///---------------------------------------------------------------------------- - -BOOL LLPanelScriptLimitsAttachment::requestAttachmentDetails() -{ - if (!gAgent.getRegion()) return FALSE; - - LLSD body; - std::string url = gAgent.getRegion()->getCapability("AttachmentResources"); - if (!url.empty()) - { - LLCoros::instance().launch("LLPanelScriptLimitsAttachment::getAttachmentLimitsCoro", - boost::bind(&LLPanelScriptLimitsAttachment::getAttachmentLimitsCoro, this, url)); - return TRUE; - } - else - { - return FALSE; - } -} - -void LLPanelScriptLimitsAttachment::getAttachmentLimitsCoro(std::string url) -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getAttachmentLimitsCoro", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - - LLSD result = httpAdapter->getAndSuspend(httpRequest, url); - - LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - - if (!status) - { - LL_WARNS() << "Unable to retrieve attachment limits." << LL_ENDL; - return; - } - - LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance("script_limits"); - - if (!instance) - { - LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL; - return; - } - - LLTabContainer* tab = instance->getChild("scriptlimits_panels"); - if (!tab) - { - LL_WARNS() << "Failed to get scriptlimits_panels" << LL_ENDL; - return; - } - - LLPanelScriptLimitsAttachment* panel = (LLPanelScriptLimitsAttachment*)tab->getChild("script_limits_my_avatar_panel"); - if (!panel) - { - LL_WARNS() << "Failed to get script_limits_my_avatar_panel" << LL_ENDL; - return; - } - - panel->getChild("loading_text")->setValue(LLSD(std::string(""))); - - LLButton* btn = panel->getChild("refresh_list_btn"); - if (btn) - { - btn->setEnabled(true); - } - - result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); - panel->setAttachmentDetails(result); -} - - -void LLPanelScriptLimitsAttachment::setAttachmentDetails(LLSD content) -{ - LLScrollListCtrl *list = getChild("scripts_list"); - - if(!list) - { - return; - } - - S32 number_attachments = content["attachments"].size(); - - for(int i = 0; i < number_attachments; i++) - { - std::string humanReadableLocation = ""; - if(content["attachments"][i].has("location")) - { - std::string actualLocation = content["attachments"][i]["location"]; - humanReadableLocation = LLTrans::getString(actualLocation.c_str()); - } - - S32 number_objects = content["attachments"][i]["objects"].size(); - for(int j = 0; j < number_objects; j++) - { - LLUUID task_id = content["attachments"][i]["objects"][j]["id"].asUUID(); - S32 size = 0; - if(content["attachments"][i]["objects"][j]["resources"].has("memory")) - { - size = content["attachments"][i]["objects"][j]["resources"]["memory"].asInteger() / SIZE_OF_ONE_KB; - } - S32 urls = 0; - if(content["attachments"][i]["objects"][j]["resources"].has("urls")) - { - urls = content["attachments"][i]["objects"][j]["resources"]["urls"].asInteger(); - } - std::string name = content["attachments"][i]["objects"][j]["name"].asString(); - - LLSD element; - - element["id"] = task_id; - element["columns"][0]["column"] = "size"; - element["columns"][0]["value"] = llformat("%d", size); - element["columns"][0]["font"] = "SANSSERIF"; - element["columns"][0]["halign"] = LLFontGL::RIGHT; - - element["columns"][1]["column"] = "urls"; - element["columns"][1]["value"] = llformat("%d", urls); - element["columns"][1]["font"] = "SANSSERIF"; - element["columns"][1]["halign"] = LLFontGL::RIGHT; - - element["columns"][2]["column"] = "name"; - element["columns"][2]["value"] = name; - element["columns"][2]["font"] = "SANSSERIF"; - - element["columns"][3]["column"] = "location"; - element["columns"][3]["value"] = humanReadableLocation; - element["columns"][3]["font"] = "SANSSERIF"; - - list->addElement(element); - } - } - - setAttachmentSummary(content); - - getChild("loading_text")->setValue(LLSD(std::string(""))); - - LLButton* btn = getChild("refresh_list_btn"); - if(btn) - { - btn->setEnabled(true); - } -} - -BOOL LLPanelScriptLimitsAttachment::postBuild() -{ - childSetAction("refresh_list_btn", onClickRefresh, this); - - std::string msg_waiting = LLTrans::getString("ScriptLimitsRequestWaiting"); - getChild("loading_text")->setValue(LLSD(msg_waiting)); - return requestAttachmentDetails(); -} - -void LLPanelScriptLimitsAttachment::clearList() -{ - LLCtrlListInterface *list = childGetListInterface("scripts_list"); - - if (list) - { - list->operateOnAll(LLCtrlListInterface::OP_DELETE); - } - - std::string msg_waiting = LLTrans::getString("ScriptLimitsRequestWaiting"); - getChild("loading_text")->setValue(LLSD(msg_waiting)); -} - -void LLPanelScriptLimitsAttachment::setAttachmentSummary(LLSD content) -{ - if(content["summary"]["used"][0]["type"].asString() == std::string("memory")) - { - mAttachmentMemoryUsed = content["summary"]["used"][0]["amount"].asInteger() / SIZE_OF_ONE_KB; - mAttachmentMemoryMax = content["summary"]["available"][0]["amount"].asInteger() / SIZE_OF_ONE_KB; - mGotAttachmentMemoryUsed = true; - } - else if(content["summary"]["used"][1]["type"].asString() == std::string("memory")) - { - mAttachmentMemoryUsed = content["summary"]["used"][1]["amount"].asInteger() / SIZE_OF_ONE_KB; - mAttachmentMemoryMax = content["summary"]["available"][1]["amount"].asInteger() / SIZE_OF_ONE_KB; - mGotAttachmentMemoryUsed = true; - } - else - { - LL_WARNS() << "attachment details don't contain memory summary info" << LL_ENDL; - return; - } - - if(content["summary"]["used"][0]["type"].asString() == std::string("urls")) - { - mAttachmentURLsUsed = content["summary"]["used"][0]["amount"].asInteger(); - mAttachmentURLsMax = content["summary"]["available"][0]["amount"].asInteger(); - mGotAttachmentURLsUsed = true; - } - else if(content["summary"]["used"][1]["type"].asString() == std::string("urls")) - { - mAttachmentURLsUsed = content["summary"]["used"][1]["amount"].asInteger(); - mAttachmentURLsMax = content["summary"]["available"][1]["amount"].asInteger(); - mGotAttachmentURLsUsed = true; - } - else - { - LL_WARNS() << "attachment details don't contain urls summary info" << LL_ENDL; - return; - } - - if((mAttachmentMemoryUsed >= 0) && (mAttachmentMemoryMax >= 0)) - { - LLStringUtil::format_map_t args_attachment_memory; - args_attachment_memory["[COUNT]"] = llformat ("%d", mAttachmentMemoryUsed); - std::string translate_message = "ScriptLimitsMemoryUsedSimple"; - - if (0 < mAttachmentMemoryMax) - { - S32 attachment_memory_available = mAttachmentMemoryMax - mAttachmentMemoryUsed; - - args_attachment_memory["[MAX]"] = llformat ("%d", mAttachmentMemoryMax); - args_attachment_memory["[AVAILABLE]"] = llformat ("%d", attachment_memory_available); - translate_message = "ScriptLimitsMemoryUsed"; - } - - getChild("memory_used")->setValue(LLTrans::getString(translate_message, args_attachment_memory)); - } - - if((mAttachmentURLsUsed >= 0) && (mAttachmentURLsMax >= 0)) - { - S32 attachment_urls_available = mAttachmentURLsMax - mAttachmentURLsUsed; - - LLStringUtil::format_map_t args_attachment_urls; - args_attachment_urls["[COUNT]"] = llformat ("%d", mAttachmentURLsUsed); - args_attachment_urls["[MAX]"] = llformat ("%d", mAttachmentURLsMax); - args_attachment_urls["[AVAILABLE]"] = llformat ("%d", attachment_urls_available); - std::string msg_attachment_urls = LLTrans::getString("ScriptLimitsURLsUsed", args_attachment_urls); - getChild("urls_used")->setValue(LLSD(msg_attachment_urls)); - } -} - -// static -void LLPanelScriptLimitsAttachment::onClickRefresh(void* userdata) -{ - LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance("script_limits"); - if(instance) - { - LLTabContainer* tab = instance->getChild("scriptlimits_panels"); - LLPanelScriptLimitsAttachment* panel_attachments = (LLPanelScriptLimitsAttachment*)tab->getChild("script_limits_my_avatar_panel"); - LLButton* btn = panel_attachments->getChild("refresh_list_btn"); - - //To stop people from hammering the refesh button and accidentally dosing themselves - enough requests can crash the viewer! - //turn the button off, then turn it on when we get a response - if(btn) - { - btn->setEnabled(false); - } - panel_attachments->clearList(); - panel_attachments->requestAttachmentDetails(); - - return; - } - else - { - LL_WARNS() << "could not find LLPanelScriptLimitsRegionMemory instance after refresh button clicked" << LL_ENDL; - return; - } -} - diff --git a/indra/newview/llfloaterscriptlimits.h b/indra/newview/llfloaterscriptlimits.h index 16450c6527..d2192f9d01 100644 --- a/indra/newview/llfloaterscriptlimits.h +++ b/indra/newview/llfloaterscriptlimits.h @@ -152,51 +152,4 @@ protected: static void onClickReturn(void* userdata); }; -///////////////////////////////////////////////////////////////////////////// -// Attachment panel -///////////////////////////////////////////////////////////////////////////// - -class LLPanelScriptLimitsAttachment : public LLPanelScriptLimitsInfo -{ - -public: - LLPanelScriptLimitsAttachment() - : LLPanelScriptLimitsInfo(), - mGotAttachmentMemoryUsed(false), - mAttachmentMemoryMax(0), - mAttachmentMemoryUsed(0), - mGotAttachmentURLsUsed(false), - mAttachmentURLsMax(0), - mAttachmentURLsUsed(0) - {}; - - ~LLPanelScriptLimitsAttachment() - { - }; - - // LLPanel - virtual BOOL postBuild(); - - void setAttachmentDetails(LLSD content); - - void setAttachmentSummary(LLSD content); - BOOL requestAttachmentDetails(); - void clearList(); - -private: - void getAttachmentLimitsCoro(std::string url); - - bool mGotAttachmentMemoryUsed; - S32 mAttachmentMemoryMax; - S32 mAttachmentMemoryUsed; - - bool mGotAttachmentURLsUsed; - S32 mAttachmentURLsMax; - S32 mAttachmentURLsUsed; - -protected: - - static void onClickRefresh(void* userdata); -}; - #endif diff --git a/indra/newview/llfloatertopobjects.cpp b/indra/newview/llfloatertopobjects.cpp index 3e6fc3dc0d..bd49405f34 100644 --- a/indra/newview/llfloatertopobjects.cpp +++ b/indra/newview/llfloatertopobjects.cpp @@ -78,8 +78,6 @@ LLFloaterTopObjects::LLFloaterTopObjects(const LLSD& key) mCommitCallbackRegistrar.add("TopObjects.ShowBeacon", boost::bind(&LLFloaterTopObjects::onClickShowBeacon, this)); mCommitCallbackRegistrar.add("TopObjects.ReturnSelected", boost::bind(&LLFloaterTopObjects::onReturnSelected, this)); mCommitCallbackRegistrar.add("TopObjects.ReturnAll", boost::bind(&LLFloaterTopObjects::onReturnAll, this)); - mCommitCallbackRegistrar.add("TopObjects.DisableSelected", boost::bind(&LLFloaterTopObjects::onDisableSelected, this)); - mCommitCallbackRegistrar.add("TopObjects.DisableAll", boost::bind(&LLFloaterTopObjects::onDisableAll, this)); mCommitCallbackRegistrar.add("TopObjects.Refresh", boost::bind(&LLFloaterTopObjects::onRefresh, this)); mCommitCallbackRegistrar.add("TopObjects.GetByObjectName", boost::bind(&LLFloaterTopObjects::onGetByObjectName, this)); mCommitCallbackRegistrar.add("TopObjects.GetByOwnerName", boost::bind(&LLFloaterTopObjects::onGetByOwnerName, this)); @@ -145,6 +143,7 @@ void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data) { U32 request_flags; U32 total_count; + U64 total_memory = 0; msg->getU32Fast(_PREHASH_RequestData, _PREHASH_RequestFlags, request_flags); msg->getU32Fast(_PREHASH_RequestData, _PREHASH_TotalObjectCount, total_count); @@ -192,6 +191,7 @@ void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data) { parcel_buf = parcel_name; script_memory = script_size; + total_memory += script_size; } } @@ -265,8 +265,10 @@ void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data) { setTitle(getString("top_scripts_title")); list->setColumnLabel("score", getString("scripts_score_label")); - + LLUIString format = getString("top_scripts_text"); + total_memory /= 1024; + format.setArg("[MEMORY]", llformat("%ld", total_memory)); format.setArg("[COUNT]", llformat("%d", total_count)); format.setArg("[TIME]", llformat("%0.3f", mtotalScore)); getChild("title_text")->setValue(LLSD(format)); @@ -332,7 +334,7 @@ void LLFloaterTopObjects::onClickShowBeacon() showBeacon(); } -void LLFloaterTopObjects::doToObjects(int action, bool all) +void LLFloaterTopObjects::returnObjects(bool all) { LLMessageSystem *msg = gMessageSystem; @@ -356,14 +358,7 @@ void LLFloaterTopObjects::doToObjects(int action, bool all) } if (start_message) { - if (action == ACTION_RETURN) - { - msg->newMessageFast(_PREHASH_ParcelReturnObjects); - } - else - { - msg->newMessageFast(_PREHASH_ParcelDisableObjects); - } + msg->newMessageFast(_PREHASH_ParcelReturnObjects); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID()); @@ -397,7 +392,7 @@ bool LLFloaterTopObjects::callbackReturnAll(const LLSD& notification, const LLSD if(!instance) return false; if (option == 0) { - instance->doToObjects(ACTION_RETURN, true); + instance->returnObjects(true); } return false; } @@ -410,31 +405,7 @@ void LLFloaterTopObjects::onReturnAll() void LLFloaterTopObjects::onReturnSelected() { - doToObjects(ACTION_RETURN, false); -} - - -//static -bool LLFloaterTopObjects::callbackDisableAll(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - LLFloaterTopObjects* instance = LLFloaterReg::getTypedInstance("top_objects"); - if(!instance) return false; - if (option == 0) - { - instance->doToObjects(ACTION_DISABLE, true); - } - return false; -} - -void LLFloaterTopObjects::onDisableAll() -{ - LLNotificationsUtil::add("DisableAllTopObjects", LLSD(), LLSD(), callbackDisableAll); -} - -void LLFloaterTopObjects::onDisableSelected() -{ - doToObjects(ACTION_DISABLE, false); + returnObjects(false); } diff --git a/indra/newview/llfloatertopobjects.h b/indra/newview/llfloatertopobjects.h index dbbe9ac521..3138249c7a 100644 --- a/indra/newview/llfloatertopobjects.h +++ b/indra/newview/llfloatertopobjects.h @@ -78,15 +78,12 @@ private: static void onDoubleClickObjectsList(void* data); void onClickShowBeacon(); - void doToObjects(int action, bool all); + void returnObjects(bool all); void onReturnAll(); void onReturnSelected(); - void onDisableAll(); - void onDisableSelected(); static bool callbackReturnAll(const LLSD& notification, const LLSD& response); - static bool callbackDisableAll(const LLSD& notification, const LLSD& response); void onGetByOwnerName(); void onGetByObjectName(); @@ -108,12 +105,6 @@ private: F32 mtotalScore; - enum - { - ACTION_RETURN = 0, - ACTION_DISABLE - }; - static LLFloaterTopObjects* sInstance; }; diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp index 76ad2146f1..db5a192287 100644 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -60,6 +60,7 @@ #include "llfloaterreg.h" #include "llscrollcontainer.h" // scroll container for overlapping elements #include "lllivefile.h" // live file poll/stat/reload +#include "llviewermenufile.h" // LLFilePickerReplyThread // Boost (for linux/unix command-line execv) #include @@ -206,7 +207,9 @@ private: void onClickSaveAll(S32 id); void onClickEditFloater(); void onClickBrowseForEditor(); + void getExecutablePath(const std::vector& filenames); void onClickBrowseForDiffs(); + void getDiffsFilePath(const std::vector& filenames); void onClickToggleDiffHighlighting(); void onClickToggleOverlapping(); void onClickCloseDisplayedFloater(S32 id); @@ -1019,15 +1022,14 @@ void LLFloaterUIPreview::onClickEditFloater() // Respond to button click to browse for an executable with which to edit XML files void LLFloaterUIPreview::onClickBrowseForEditor() { - // Let the user choose an executable through the file picker dialog box - LLFilePicker& picker = LLFilePicker::instance(); - if (!picker.getOpenFile(LLFilePicker::FFLOAD_EXE)) - { - return; // user cancelled -- do nothing - } + // Let the user choose an executable through the file picker dialog box + (new LLFilePickerReplyThread(boost::bind(&LLFloaterUIPreview::getExecutablePath, this, _1), LLFilePicker::FFLOAD_EXE, false))->getFile(); +} +void LLFloaterUIPreview::getExecutablePath(const std::vector& filenames) +{ // put the selected path into text field - const std::string chosen_path = picker.getFirstFile(); + const std::string chosen_path = filenames[0]; std::string executable_path = chosen_path; #if LL_DARWIN // on Mac, if it's an application bundle, figure out the actual path from the Info.plist file @@ -1075,15 +1077,13 @@ void LLFloaterUIPreview::onClickBrowseForEditor() void LLFloaterUIPreview::onClickBrowseForDiffs() { // create load dialog box - LLFilePicker::ELoadFilter type = (LLFilePicker::ELoadFilter)((intptr_t)((void*)LLFilePicker::FFLOAD_XML)); // nothing for *.exe so just use all - LLFilePicker& picker = LLFilePicker::instance(); - if (!picker.getOpenFile(type)) // user cancelled -- do nothing - { - return; - } + (new LLFilePickerReplyThread(boost::bind(&LLFloaterUIPreview::getDiffsFilePath, this, _1), LLFilePicker::FFLOAD_XML, false))->getFile(); +} +void LLFloaterUIPreview::getDiffsFilePath(const std::vector& filenames) +{ // put the selected path into text field - const std::string chosen_path = picker.getFirstFile(); + const std::string chosen_path = filenames[0]; mDiffPathTextBox->setText(std::string(chosen_path)); // copy the path to the executable to the textfield for display and later fetching if(LLView::sHighlightingDiffs) // if we're already highlighting, toggle off and then on so we get the data from the new file { diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index e76b3d118e..d59c301210 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -854,15 +854,33 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, } else // IM_TASK_INVENTORY_OFFERED { - if (sizeof(S8) != binary_bucket_size) + if (offline == IM_OFFLINE && session_id.isNull() && aux_id.notNull() && binary_bucket_size > sizeof(S8)* 5) { - LL_WARNS("Messaging") << "Malformed inventory offer from object" << LL_ENDL; - delete info; - break; + // cap received offline message + std::string str_bucket = ll_safe_string((char*)binary_bucket, binary_bucket_size); + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("|", "", boost::keep_empty_tokens); + tokenizer tokens(str_bucket, sep); + tokenizer::iterator iter = tokens.begin(); + + info->mType = (LLAssetType::EType)(atoi((*(iter++)).c_str())); + // Note There is more elements in 'tokens' ... + + info->mObjectID = LLUUID::null; + info->mFromObject = TRUE; + } + else + { + if (sizeof(S8) != binary_bucket_size) + { + LL_WARNS("Messaging") << "Malformed inventory offer from object" << LL_ENDL; + delete info; + break; + } + info->mType = (LLAssetType::EType) binary_bucket[0]; + info->mObjectID = LLUUID::null; + info->mFromObject = TRUE; } - info->mType = (LLAssetType::EType) binary_bucket[0]; - info->mObjectID = LLUUID::null; - info->mFromObject = TRUE; } info->mIM = dialog; diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 1987e15850..074b0c9c14 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -1415,7 +1415,7 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, break; default: - LL_INFOS() << "Unhandled asset type (llassetstorage.h): " + LL_INFOS_ONCE() << "Unhandled asset type (llassetstorage.h): " << (S32)asset_type << " (" << LLAssetType::lookup(asset_type) << ")" << LL_ENDL; break; } @@ -6307,7 +6307,7 @@ bool confirm_attachment_rez(const LLSD& notification, const LLSD& response) if (!gAgentAvatarp->canAttachMoreObjects()) { LLSD args; - args["MAX_ATTACHMENTS"] = llformat("%d", MAX_AGENT_ATTACHMENTS); + args["MAX_ATTACHMENTS"] = llformat("%d", gAgentAvatarp->getMaxAttachments()); LLNotificationsUtil::add("MaxAttachmentsOnOutfit", args); return false; } @@ -7344,7 +7344,10 @@ void LLFolderViewGroupedItemBridge::groupFilterContextMenu(folder_view_item_dequ { if (!LLAppearanceMgr::instance().canAddWearables(ids) && canWearSelected(ids)) { - disabled_items.push_back(std::string("Wearable Add")); + disabled_items.push_back(std::string("Wearable And Object Wear")); + disabled_items.push_back(std::string("Wearable Add")); + disabled_items.push_back(std::string("Attach To")); + disabled_items.push_back(std::string("Attach To HUD")); } } disable_context_entries_if_present(menu, disabled_items); diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index a520e0171e..b140c7c38e 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1820,9 +1820,19 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item) if (LLAssetType::lookup(item->getType()) == LLAssetType::badLookup()) { - LL_WARNS(LOG_INV) << "Got unknown asset type for item [ name: " << item->getName() - << " type: " << item->getType() - << " inv-type: " << item->getInventoryType() << " ]." << LL_ENDL; + if (item->getType() >= LLAssetType::AT_COUNT) + { + // Not yet supported. + LL_DEBUGS(LOG_INV) << "Got unknown asset type for item [ name: " << item->getName() + << " type: " << item->getType() + << " inv-type: " << item->getInventoryType() << " ]." << LL_ENDL; + } + else + { + LL_WARNS(LOG_INV) << "Got unknown asset type for item [ name: " << item->getName() + << " type: " << item->getType() + << " inv-type: " << item->getInventoryType() << " ]." << LL_ENDL; + } } // This condition means that we tried to add a link without the baseobj being in memory. diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index 3992b506e9..d4993a1091 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -871,7 +871,8 @@ LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id) if (objectp->getType() >= LLAssetType::AT_COUNT) { - LL_WARNS() << "LLInventoryPanel::buildNewViews called with unknown objectp->mType : " + // Example: Happens when we add assets of new, not yet supported type to library + LL_DEBUGS() << "LLInventoryPanel::buildNewViews called with unknown objectp->mType : " << ((S32) objectp->getType()) << " name " << objectp->getName() << " UUID " << objectp->getUUID() << LL_ENDL; diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index c535fc1cdf..1bdeddbcfe 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -516,7 +516,7 @@ LLMutex* LLLogChat::historyThreadsMutex() { if (sHistoryThreadsMutex == NULL) { - sHistoryThreadsMutex = new LLMutex(NULL); + sHistoryThreadsMutex = new LLMutex(); } return sHistoryThreadsMutex; } @@ -573,40 +573,10 @@ void LLLogChat::findTranscriptFiles(std::string pattern, std::vectoradd(dirname, filename); - - LLFILE * filep = LLFile::fopen(fullname, "rb"); - if (NULL != filep) + if (isTranscriptFileFound(fullname)) { - if(makeLogFileName("chat")== fullname) - { - //Add Nearby chat history to the list of transcriptions - list_of_transcriptions.push_back(gDirUtilp->add(dirname, filename)); - LLFile::close(filep); - continue; - } - char buffer[LOG_RECALL_SIZE]; - - fseek(filep, 0, SEEK_END); // seek to end of file - S32 bytes_to_read = ftell(filep); // get current file pointer - fseek(filep, 0, SEEK_SET); // seek back to beginning of file - - // limit the number characters to read from file - if (bytes_to_read >= LOG_RECALL_SIZE) - { - bytes_to_read = LOG_RECALL_SIZE - 1; - } - - if (bytes_to_read > 0 && NULL != fgets(buffer, bytes_to_read, filep)) - { - //matching a timestamp - boost::match_results matches; - if (boost::regex_match(std::string(buffer), matches, TIMESTAMP)) - { - list_of_transcriptions.push_back(gDirUtilp->add(dirname, filename)); - } - } - LLFile::close(filep); - } + list_of_transcriptions.push_back(fullname); + } } } @@ -756,75 +726,70 @@ void LLLogChat::deleteTranscripts() // static bool LLLogChat::isTranscriptExist(const LLUUID& avatar_id, bool is_group) { - std::vector list_of_transcriptions; - LLLogChat::getListOfTranscriptFiles(list_of_transcriptions); - - if (list_of_transcriptions.size() > 0) + LLAvatarName avatar_name; + LLAvatarNameCache::get(avatar_id, &avatar_name); + std::string avatar_user_name = avatar_name.getAccountName(); + if(!is_group) { - LLAvatarName avatar_name; - LLAvatarNameCache::get(avatar_id, &avatar_name); - std::string avatar_user_name = avatar_name.getAccountName(); - if(!is_group) - { - std::replace(avatar_user_name.begin(), avatar_user_name.end(), '.', '_'); - BOOST_FOREACH(std::string& transcript_file_name, list_of_transcriptions) - { - if (std::string::npos != transcript_file_name.find(avatar_user_name)) - { - return true; - } - } - } - else - { - std::string file_name; - gCacheName->getGroupName(avatar_id, file_name); - file_name = makeLogFileName(file_name); - BOOST_FOREACH(std::string& transcript_file_name, list_of_transcriptions) - { - if (transcript_file_name == file_name) - { - return true; - } - } - } - + std::replace(avatar_user_name.begin(), avatar_user_name.end(), '.', '_'); + return isTranscriptFileFound(makeLogFileName(avatar_user_name)); + } + else + { + std::string file_name; + gCacheName->getGroupName(avatar_id, file_name); + file_name = makeLogFileName(file_name); + return isTranscriptFileFound(makeLogFileName(file_name)); } - return false; } bool LLLogChat::isNearbyTranscriptExist() { - std::vector list_of_transcriptions; - LLLogChat::getListOfTranscriptFiles(list_of_transcriptions); - - std::string file_name; - file_name = makeLogFileName("chat"); - BOOST_FOREACH(std::string& transcript_file_name, list_of_transcriptions) - { - if (transcript_file_name == file_name) - { - return true; - } - } - return false; + return isTranscriptFileFound(makeLogFileName("chat"));; } bool LLLogChat::isAdHocTranscriptExist(std::string file_name) { - std::vector list_of_transcriptions; - LLLogChat::getListOfTranscriptFiles(list_of_transcriptions); + return isTranscriptFileFound(makeLogFileName(file_name));; +} - file_name = makeLogFileName(file_name); - BOOST_FOREACH(std::string& transcript_file_name, list_of_transcriptions) +// static +bool LLLogChat::isTranscriptFileFound(std::string fullname) +{ + bool result = false; + LLFILE * filep = LLFile::fopen(fullname, "rb"); + if (NULL != filep) { - if (transcript_file_name == file_name) - { - return true; + if (makeLogFileName("chat") == fullname) + { + LLFile::close(filep); + return true; } + char buffer[LOG_RECALL_SIZE]; + + fseek(filep, 0, SEEK_END); // seek to end of file + S32 bytes_to_read = ftell(filep); // get current file pointer + fseek(filep, 0, SEEK_SET); // seek back to beginning of file + + // limit the number characters to read from file + if (bytes_to_read >= LOG_RECALL_SIZE) + { + bytes_to_read = LOG_RECALL_SIZE - 1; + } + + if (bytes_to_read > 0 && NULL != fgets(buffer, bytes_to_read, filep)) + { + //matching a timestamp + boost::match_results matches; + if (boost::regex_match(std::string(buffer), matches, TIMESTAMP)) + { + result = true; + } + } + LLFile::close(filep); } - return false; + return result; } //*TODO mark object's names in a special way so that they will be distinguishable form avatar name @@ -1012,8 +977,8 @@ void LLDeleteHistoryThread::run() LLActionThread::LLActionThread(const std::string& name) : LLThread(name), - mMutex(NULL), - mRunCondition(NULL), + mMutex(), + mRunCondition(), mFinished(false) { } diff --git a/indra/newview/lllogchat.h b/indra/newview/lllogchat.h index 6022e539a9..fcbd38a044 100644 --- a/indra/newview/lllogchat.h +++ b/indra/newview/lllogchat.h @@ -121,6 +121,7 @@ public: static bool isTranscriptExist(const LLUUID& avatar_id, bool is_group=false); static bool isNearbyTranscriptExist(); static bool isAdHocTranscriptExist(std::string file_name); + static bool isTranscriptFileFound(std::string fullname); static bool historyThreadsFinished(LLUUID session_id); static LLLoadHistoryThread* getLoadHistoryThread(LLUUID session_id); diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index df040d8f13..8a69acb8dc 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -63,6 +63,9 @@ #include const S32 LOGIN_MAX_RETRIES = 3; +const F32 LOGIN_SRV_TIMEOUT_MIN = 10; +const F32 LOGIN_SRV_TIMEOUT_MAX = 120; +const F32 LOGIN_DNS_TIMEOUT_FACTOR = 0.9; // make DNS wait shorter then retry time class LLLoginInstance::Disposable { public: @@ -237,8 +240,10 @@ void LLLoginInstance::constructAuthParams(LLPointer user_credentia // Specify desired timeout/retry options LLSD http_params; - http_params["timeout"] = gSavedSettings.getF32("LoginSRVTimeout"); + F32 srv_timeout = llclamp(gSavedSettings.getF32("LoginSRVTimeout"), LOGIN_SRV_TIMEOUT_MIN, LOGIN_SRV_TIMEOUT_MAX); + http_params["timeout"] = srv_timeout; http_params["retries"] = LOGIN_MAX_RETRIES; + http_params["DNSCacheTimeout"] = srv_timeout * LOGIN_DNS_TIMEOUT_FACTOR; //Default: indefinite mRequestData.clear(); mRequestData["method"] = "login_to_simulator"; diff --git a/indra/newview/llmainlooprepeater.cpp b/indra/newview/llmainlooprepeater.cpp index db8d2e4ede..6736e9a950 100644 --- a/indra/newview/llmainlooprepeater.cpp +++ b/indra/newview/llmainlooprepeater.cpp @@ -46,7 +46,7 @@ void LLMainLoopRepeater::start(void) { if(mQueue != 0) return; - mQueue = new LLThreadSafeQueue(gAPRPoolp, 1024); + mQueue = new LLThreadSafeQueue(1024); mMainLoopConnection = LLEventPumps::instance(). obtain("mainloop").listen(LLEventPump::inventName(), boost::bind(&LLMainLoopRepeater::onMainLoop, this, _1)); mRepeaterConnection = LLEventPumps::instance(). diff --git a/indra/newview/llmanip.cpp b/indra/newview/llmanip.cpp index 8567180dd6..6589aa477f 100644 --- a/indra/newview/llmanip.cpp +++ b/indra/newview/llmanip.cpp @@ -431,7 +431,6 @@ void LLManip::renderXYZ(const LLVector3 &vec) { const S32 PAD = 10; std::string feedback_string; - LLVector3 camera_pos = LLViewerCamera::getInstance()->getOrigin() + LLViewerCamera::getInstance()->getAtAxis(); S32 window_center_x = gViewerWindow->getWorldViewRectScaled().getWidth() / 2; S32 window_center_y = gViewerWindow->getWorldViewRectScaled().getHeight() / 2; S32 vertical_offset = window_center_y - VERTICAL_OFFSET; @@ -442,46 +441,55 @@ void LLManip::renderXYZ(const LLVector3 &vec) LLUIImagePtr imagep = LLUI::getUIImage("Rounded_Square"); gViewerWindow->setup2DRender(); const LLVector2& display_scale = gViewerWindow->getDisplayScale(); - gGL.scalef(display_scale.mV[VX], display_scale.mV[VY], 1.f); gGL.color4f(0.f, 0.f, 0.f, 0.7f); imagep->draw( - window_center_x - 115, - window_center_y + vertical_offset - PAD, - 235, - PAD * 2 + 10, + (window_center_x - 115) * display_scale.mV[VX], + (window_center_y + vertical_offset - PAD) * display_scale.mV[VY], + 235 * display_scale.mV[VX], + (PAD * 2 + 10) * display_scale.mV[VY], LLColor4(0.f, 0.f, 0.f, 0.7f) ); - } - gGL.popMatrix(); - gViewerWindow->setup3DRender(); + LLFontGL* font = LLFontGL::getFontSansSerif(); + LLLocale locale(LLLocale::USER_LOCALE); + LLGLDepthTest gls_depth(GL_FALSE); - { - LLFontGL* font = LLFontGL::getFontSansSerif(); - LLLocale locale(LLLocale::USER_LOCALE); - LLGLDepthTest gls_depth(GL_FALSE); - // render drop shadowed text - feedback_string = llformat("X: %.3f", vec.mV[VX]); - hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *font, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -102.f + 1.f, (F32)vertical_offset - 1.f, LLColor4::black, FALSE); + // render drop shadowed text (manually because of bigger 'distance') + F32 right_x; + feedback_string = llformat("X: %.3f", vec.mV[VX]); + font->render(utf8str_to_wstring(feedback_string), 0, window_center_x - 102.f + 1.f, window_center_y + vertical_offset - 2.f, LLColor4::black, + LLFontGL::LEFT, LLFontGL::BASELINE, + LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, 1000, &right_x); - feedback_string = llformat("Y: %.3f", vec.mV[VY]); - hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *font, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -27.f + 1.f, (F32)vertical_offset - 1.f, LLColor4::black, FALSE); - - feedback_string = llformat("Z: %.3f", vec.mV[VZ]); - hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *font, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, 48.f + 1.f, (F32)vertical_offset - 1.f, LLColor4::black, FALSE); + feedback_string = llformat("Y: %.3f", vec.mV[VY]); + font->render(utf8str_to_wstring(feedback_string), 0, window_center_x - 27.f + 1.f, window_center_y + vertical_offset - 2.f, LLColor4::black, + LLFontGL::LEFT, LLFontGL::BASELINE, + LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, 1000, &right_x); - // render text on top - feedback_string = llformat("X: %.3f", vec.mV[VX]); - hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *font, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -102.f, (F32)vertical_offset, LLColor4(1.f, 0.5f, 0.5f, 1.f), FALSE); + feedback_string = llformat("Z: %.3f", vec.mV[VZ]); + font->render(utf8str_to_wstring(feedback_string), 0, window_center_x + 48.f + 1.f, window_center_y + vertical_offset - 2.f, LLColor4::black, + LLFontGL::LEFT, LLFontGL::BASELINE, + LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, 1000, &right_x); - gGL.diffuseColor3f(0.5f, 1.f, 0.5f); - feedback_string = llformat("Y: %.3f", vec.mV[VY]); - hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *font, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -27.f, (F32)vertical_offset, LLColor4(0.5f, 1.f, 0.5f, 1.f), FALSE); - - gGL.diffuseColor3f(0.5f, 0.5f, 1.f); - feedback_string = llformat("Z: %.3f", vec.mV[VZ]); - hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *font, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, 48.f, (F32)vertical_offset, LLColor4(0.5f, 0.5f, 1.f, 1.f), FALSE); - } + // render text on top + feedback_string = llformat("X: %.3f", vec.mV[VX]); + font->render(utf8str_to_wstring(feedback_string), 0, window_center_x - 102.f, window_center_y + vertical_offset, LLColor4(1.f, 0.5f, 0.5f, 1.f), + LLFontGL::LEFT, LLFontGL::BASELINE, + LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, 1000, &right_x); + + feedback_string = llformat("Y: %.3f", vec.mV[VY]); + font->render(utf8str_to_wstring(feedback_string), 0, window_center_x - 27.f, window_center_y + vertical_offset, LLColor4(0.5f, 1.f, 0.5f, 1.f), + LLFontGL::LEFT, LLFontGL::BASELINE, + LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, 1000, &right_x); + + feedback_string = llformat("Z: %.3f", vec.mV[VZ]); + font->render(utf8str_to_wstring(feedback_string), 0, window_center_x + 48.f, window_center_y + vertical_offset, LLColor4(0.5f, 0.5f, 1.f, 1.f), + LLFontGL::LEFT, LLFontGL::BASELINE, + LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, 1000, &right_x); + } + gGL.popMatrix(); + + gViewerWindow->setup3DRender(); } void LLManip::renderTickText(const LLVector3& pos, const std::string& text, const LLColor4 &color) diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index e38bd8846d..38fd2d777e 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -26,10 +26,11 @@ #include "llviewerprecompiledheaders.h" +#include "llapr.h" +#include "apr_portable.h" #include "apr_pools.h" #include "apr_dso.h" #include "llhttpconstants.h" -#include "llapr.h" #include "llmeshrepository.h" #include "llagent.h" @@ -830,9 +831,9 @@ LLMeshRepoThread::LLMeshRepoThread() { LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp()); - mMutex = new LLMutex(NULL); - mHeaderMutex = new LLMutex(NULL); - mSignal = new LLCondition(NULL); + mMutex = new LLMutex(); + mHeaderMutex = new LLMutex(); + mSignal = new LLCondition(); mHttpRequest = new LLCore::HttpRequest; mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); mHttpOptions->setTransferTimeout(SMALL_MESH_XFER_TIMEOUT); @@ -1822,7 +1823,22 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat return false; } - header_size += stream.tellg(); + if (!header.isMap()) + { + LL_WARNS(LOG_MESH) << "Mesh header is invalid for ID: " << mesh_id << LL_ENDL; + return false; + } + + if (header.has("version") && header["version"].asInteger() > MAX_MESH_VERSION) + { + LL_INFOS(LOG_MESH) << "Wrong version in header for " << mesh_id << LL_ENDL; + header["404"] = 1; + } + // make sure there is at least one lod, function returns -1 and marks as 404 otherwise + else if (LLMeshRepository::getActualMeshLOD(header, 0) >= 0) + { + header_size += stream.tellg(); + } } else { @@ -2039,7 +2055,7 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data, mUploadSkin = upload_skin; mUploadJoints = upload_joints; mLockScaleIfJointPosition = lock_scale_if_joint_position; - mMutex = new LLMutex(NULL); + mMutex = new LLMutex(); mPendingUploads = 0; mFinished = false; mOrigin = gAgent.getPositionAgent(); @@ -2174,7 +2190,6 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) std::map mesh_index; std::string model_name; - std::string model_metric; S32 instance_num = 0; @@ -2204,11 +2219,6 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) model_name = data.mBaseModel->getName(); } - if (model_metric.empty()) - { - model_metric = data.mBaseModel->getMetric(); - } - std::stringstream ostr; LLModel::Decomposition& decomp = @@ -2363,11 +2373,6 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) model_name = data.mBaseModel->getName(); } - if (model_metric.empty()) - { - model_metric = data.mBaseModel->getMetric(); - } - std::stringstream ostr; LLModel::Decomposition& decomp = @@ -2498,8 +2503,7 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) if (model_name.empty()) model_name = "mesh model"; result["name"] = model_name; - if (model_metric.empty()) model_metric = "MUT_Unspecified"; - res["metric"] = model_metric; + res["metric"] = "MUT_Unspecified"; result["asset_resources"] = res; dump_llsd_to_file(result,make_dump_name("whole_model_",dump_num)); @@ -2919,9 +2923,14 @@ S32 LLMeshRepository::getActualMeshLOD(LLSD& header, S32 lod) { lod = llclamp(lod, 0, 3); + if (header.has("404")) + { + return -1; + } + S32 version = header["version"]; - if (header.has("404") || version > MAX_MESH_VERSION) + if (version > MAX_MESH_VERSION) { return -1; } @@ -3168,8 +3177,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b if (header_bytes > 0 && !header.has("404") - && header.has("version") - && header["version"].asInteger() <= MAX_MESH_VERSION) + && (!header.has("version") || header["version"].asInteger() <= MAX_MESH_VERSION)) { std::stringstream str; @@ -3458,7 +3466,7 @@ LLMeshRepository::LLMeshRepository() void LLMeshRepository::init() { - mMeshMutex = new LLMutex(NULL); + mMeshMutex = new LLMutex(); LLConvexDecomposition::getInstance()->initSystem(); @@ -4302,10 +4310,13 @@ F32 LLMeshRepository::getStreamingCostLegacy(LLSD& header, F32 radius, S32* byte F32 dlow = llmin(radius/0.06f, max_distance); F32 dmid = llmin(radius/0.24f, max_distance); - F32 METADATA_DISCOUNT = (F32) gSavedSettings.getU32("MeshMetaDataDiscount"); //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead - F32 MINIMUM_SIZE = (F32) gSavedSettings.getU32("MeshMinimumByteSize"); //make sure nothing is "free" + static LLCachedControl metadata_discount_ch(gSavedSettings, "MeshMetaDataDiscount", 384); //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead + static LLCachedControl minimum_size_ch(gSavedSettings, "MeshMinimumByteSize", 16); //make sure nothing is "free" + static LLCachedControl bytes_per_triangle_ch(gSavedSettings, "MeshBytesPerTriangle", 16); - F32 bytes_per_triangle = (F32) gSavedSettings.getU32("MeshBytesPerTriangle"); + F32 metadata_discount = (F32)metadata_discount_ch; + F32 minimum_size = (F32)minimum_size_ch; + F32 bytes_per_triangle = (F32)bytes_per_triangle_ch; S32 bytes_lowest = header["lowest_lod"]["size"].asInteger(); S32 bytes_low = header["low_lod"]["size"].asInteger(); @@ -4332,10 +4343,10 @@ F32 LLMeshRepository::getStreamingCostLegacy(LLSD& header, F32 radius, S32* byte bytes_lowest = bytes_low; } - F32 triangles_lowest = llmax((F32) bytes_lowest-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; - F32 triangles_low = llmax((F32) bytes_low-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; - F32 triangles_mid = llmax((F32) bytes_mid-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; - F32 triangles_high = llmax((F32) bytes_high-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; + F32 triangles_lowest = llmax((F32) bytes_lowest-metadata_discount, minimum_size)/bytes_per_triangle; + F32 triangles_low = llmax((F32) bytes_low-metadata_discount, minimum_size)/bytes_per_triangle; + F32 triangles_mid = llmax((F32) bytes_mid-metadata_discount, minimum_size)/bytes_per_triangle; + F32 triangles_high = llmax((F32) bytes_high-metadata_discount, minimum_size)/bytes_per_triangle; if (bytes) { @@ -4429,13 +4440,13 @@ bool LLMeshCostData::init(const LLSD& header) mSizeByLOD[2] = bytes_med; mSizeByLOD[3] = bytes_high; - F32 METADATA_DISCOUNT = (F32) gSavedSettings.getU32("MeshMetaDataDiscount"); //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead - F32 MINIMUM_SIZE = (F32) gSavedSettings.getU32("MeshMinimumByteSize"); //make sure nothing is "free" - F32 bytes_per_triangle = (F32) gSavedSettings.getU32("MeshBytesPerTriangle"); + static LLCachedControl metadata_discount(gSavedSettings, "MeshMetaDataDiscount", 384); //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead + static LLCachedControl minimum_size(gSavedSettings, "MeshMinimumByteSize", 16); //make sure nothing is "free" + static LLCachedControl bytes_per_triangle(gSavedSettings, "MeshBytesPerTriangle", 16); for (S32 i=0; i<4; i++) { - mEstTrisByLOD[i] = llmax((F32) mSizeByLOD[i]-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; + mEstTrisByLOD[i] = llmax((F32)mSizeByLOD[i] - (F32)metadata_discount, (F32)minimum_size) / (F32)bytes_per_triangle; } return true; @@ -4597,8 +4608,8 @@ LLPhysicsDecomp::LLPhysicsDecomp() mQuitting = false; mDone = false; - mSignal = new LLCondition(NULL); - mMutex = new LLMutex(NULL); + mSignal = new LLCondition(); + mMutex = new LLMutex(); } LLPhysicsDecomp::~LLPhysicsDecomp() diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp index 301487b994..19f238d99a 100644 --- a/indra/newview/llmoveview.cpp +++ b/indra/newview/llmoveview.cpp @@ -702,11 +702,9 @@ void LLPanelStandStopFlying::updatePosition() { if (mAttached) return; - S32 y_pos = 0; S32 bottom_tb_center = 0; if (LLToolBar* toolbar_bottom = gToolBarView->getToolbar(LLToolBarEnums::TOOLBAR_BOTTOM)) { - y_pos = toolbar_bottom->getRect().getHeight(); bottom_tb_center = toolbar_bottom->getRect().getCenterX(); } @@ -716,20 +714,6 @@ void LLPanelStandStopFlying::updatePosition() left_tb_width = toolbar_left->getRect().getWidth(); } - if (!mStateManagementButtons.get()) // Obsolete?!! - { - LLPanel* panel_ssf_container = gToolBarView->getChild("state_management_buttons_container"); - if (panel_ssf_container) - { - mStateManagementButtons = panel_ssf_container->getHandle(); - } - } - - if(LLPanel* panel_ssf_container = mStateManagementButtons.get()) - { - panel_ssf_container->setOrigin(0, y_pos); - } - if (gToolBarView != NULL && gToolBarView->getToolbar(LLToolBarEnums::TOOLBAR_LEFT)->hasButtons()) { S32 x_pos = bottom_tb_center - getRect().getWidth() / 2 - left_tb_width; diff --git a/indra/newview/llmoveview.h b/indra/newview/llmoveview.h index 4a31f2a814..e8b9a6fdb2 100644 --- a/indra/newview/llmoveview.h +++ b/indra/newview/llmoveview.h @@ -172,8 +172,6 @@ private: */ LLHandle mOriginalParent; - LLHandle mStateManagementButtons; - /** * True if the panel is currently attached to the movement controls floater. * diff --git a/indra/newview/llnotificationlistitem.cpp b/indra/newview/llnotificationlistitem.cpp index a5bc75e6bd..b405d3dca2 100644 --- a/indra/newview/llnotificationlistitem.cpp +++ b/indra/newview/llnotificationlistitem.cpp @@ -135,7 +135,8 @@ std::string LLNotificationListItem::buildNotificationDate(const LLDate& time_sta +LLTrans::getString("TimeDay")+"]/[" +LLTrans::getString("TimeYear")+"] [" +LLTrans::getString("TimeHour")+"]:[" - +LLTrans::getString("TimeMin")+"]"; + +LLTrans::getString("TimeMin")+"] [" + +LLTrans::getString("TimeTimezone")+"]"; break; } LLSD substitution; @@ -376,13 +377,13 @@ BOOL LLGroupNoticeNotificationListItem::postBuild() mTitleBoxExp->setValue(mParams.subject); mNoticeTextExp->setValue(mParams.message); - mTimeBox->setValue(buildNotificationDate(mParams.time_stamp, UTC)); - mTimeBoxExp->setValue(buildNotificationDate(mParams.time_stamp, UTC)); + mTimeBox->setValue(buildNotificationDate(mParams.time_stamp)); + mTimeBoxExp->setValue(buildNotificationDate(mParams.time_stamp)); //Workaround: in case server timestamp is 0 - we use the time when notification was actually received if (mParams.time_stamp.isNull()) { - mTimeBox->setValue(buildNotificationDate(mParams.received_time, UTC)); - mTimeBoxExp->setValue(buildNotificationDate(mParams.received_time, UTC)); + mTimeBox->setValue(buildNotificationDate(mParams.received_time)); + mTimeBoxExp->setValue(buildNotificationDate(mParams.received_time)); } setSender(mParams.sender); diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 892fa385d7..f2a284a561 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -621,8 +621,14 @@ void LLOutfitsList::applyFilterToTab( bool LLOutfitsList::canWearSelected() { + if (!isAgentAvatarValid()) + { + return false; + } + uuid_vec_t selected_items; getSelectedItemsUUIDs(selected_items); + S32 nonreplacable_objects = 0; for (uuid_vec_t::const_iterator it = selected_items.begin(); it != selected_items.end(); ++it) { @@ -633,10 +639,21 @@ bool LLOutfitsList::canWearSelected() { return false; } + + const LLViewerInventoryItem* item = gInventory.getItem(id); + if (!item) + { + return false; + } + + if (item->getType() == LLAssetType::AT_OBJECT) + { + nonreplacable_objects++; + } } - // All selected items can be worn. - return true; + // All selected items can be worn. But do we have enough space for them? + return nonreplacable_objects == 0 || gAgentAvatarp->canAttachMoreObjects(nonreplacable_objects); } void LLOutfitsList::wearSelectedItems() diff --git a/indra/newview/lloutputmonitorctrl.cpp b/indra/newview/lloutputmonitorctrl.cpp index 6c26073d5b..7f6c065bb9 100644 --- a/indra/newview/lloutputmonitorctrl.cpp +++ b/indra/newview/lloutputmonitorctrl.cpp @@ -72,9 +72,11 @@ LLOutputMonitorCtrl::LLOutputMonitorCtrl(const LLOutputMonitorCtrl::Params& p) mImageLevel3(p.image_level_3), mAutoUpdate(p.auto_update), mSpeakerId(p.speaker_id), + mIsModeratorMuted(false), mIsAgentControl(false), mIndicatorToggled(false), - mShowParticipantsSpeaking(false) + mShowParticipantsSpeaking(false), + mChannelState(INACTIVE_CHANNEL) { //static LLUIColor output_monitor_muted_color = LLUIColorTable::instance().getColor("OutputMonitorMutedColor", LLColor4::orange); //static LLUIColor output_monitor_overdriven_color = LLUIColorTable::instance().getColor("OutputMonitorOverdrivenColor", LLColor4::red); @@ -124,7 +126,7 @@ void LLOutputMonitorCtrl::draw() const F32 LEVEL_1 = LLVoiceClient::OVERDRIVEN_POWER_LEVEL * 2.f / 3.f; const F32 LEVEL_2 = LLVoiceClient::OVERDRIVEN_POWER_LEVEL; - if (getVisible() && mAutoUpdate && !mIsMuted && mSpeakerId.notNull()) + if (getVisible() && mAutoUpdate && !getIsMuted() && mSpeakerId.notNull()) { setPower(LLVoiceClient::getInstance()->getCurrentPower(mSpeakerId)); if(mIsAgentControl) @@ -156,7 +158,7 @@ void LLOutputMonitorCtrl::draw() } LLPointer icon; - if (mIsMuted) + if (getIsMuted()) { icon = mImageMute; } @@ -255,6 +257,21 @@ BOOL LLOutputMonitorCtrl::handleMouseUp(S32 x, S32 y, MASK mask) return TRUE; } +void LLOutputMonitorCtrl::setIsActiveChannel(bool val) +{ + setChannelState(val ? ACTIVE_CHANNEL : INACTIVE_CHANNEL); +} + +void LLOutputMonitorCtrl::setChannelState(EChannelState state) +{ + mChannelState = state; + if (state == INACTIVE_CHANNEL) + { + // switchIndicator will set it to TRUE when channel becomes active + setVisible(FALSE); + } +} + void LLOutputMonitorCtrl::setSpeakerId(const LLUUID& speaker_id, const LLUUID& session_id/* = LLUUID::null*/, bool show_other_participants_speaking /* = false */) { if (speaker_id.isNull() && mSpeakerId.notNull()) @@ -304,8 +321,7 @@ void LLOutputMonitorCtrl::onChange() // virtual void LLOutputMonitorCtrl::switchIndicator(bool switch_on) { - - if(getVisible() != (BOOL)switch_on) + if ((mChannelState != INACTIVE_CHANNEL) && (getVisible() != (BOOL)switch_on)) { setVisible(switch_on); diff --git a/indra/newview/lloutputmonitorctrl.h b/indra/newview/lloutputmonitorctrl.h index 0682af1278..98966d39ee 100644 --- a/indra/newview/lloutputmonitorctrl.h +++ b/indra/newview/lloutputmonitorctrl.h @@ -72,13 +72,26 @@ public: void setPower(F32 val); F32 getPower(F32 val) const { return mPower; } - + + bool getIsMuted() const { return (mIsMuted || mIsModeratorMuted); } + void setIsModeratorMuted(bool val) { mIsModeratorMuted = val; } + // For the current user, need to know the PTT state to show // correct button image. void setIsAgentControl(bool val) { mIsAgentControl = val; } - void setIsTalking(bool val) { mIsTalking = val; } + enum EChannelState + { + ACTIVE_CHANNEL, + INACTIVE_CHANNEL, + UNDEFINED_CHANNEL + }; + + // switchIndicator controls visibility, 'active channel' governs if we are allowed to show indicator + void setIsActiveChannel(bool val); + void setChannelState(EChannelState state); + void setShowParticipantsSpeaking(bool show) { mShowParticipantsSpeaking = show; } /** @@ -131,6 +144,7 @@ private: F32 mPower; bool mIsAgentControl; + bool mIsModeratorMuted; bool mIsMuted; bool mIsTalking; bool mShowParticipantsSpeaking; @@ -148,6 +162,8 @@ private: LLUUID mSpeakerId; bool mIndicatorToggled; + + EChannelState mChannelState; }; #endif diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index b9b97f4cce..6d0c30fbf3 100644 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -628,12 +628,9 @@ BOOL LLPanelClassifiedEdit::postBuild() { LLPanelClassifiedInfo::postBuild(); - LLTextureCtrl* snapshot = getChild("classified_snapshot"); - snapshot->setOnSelectCallback(boost::bind(&LLPanelClassifiedEdit::onChange, this)); - LLUICtrl* edit_icon = getChild("edit_icon"); - snapshot->setMouseEnterCallback(boost::bind(&LLPanelClassifiedEdit::onTexturePickerMouseEnter, this, edit_icon)); - snapshot->setMouseLeaveCallback(boost::bind(&LLPanelClassifiedEdit::onTexturePickerMouseLeave, this, edit_icon)); + mSnapshotCtrl->setMouseEnterCallback(boost::bind(&LLPanelClassifiedEdit::onTexturePickerMouseEnter, this, edit_icon)); + mSnapshotCtrl->setMouseLeaveCallback(boost::bind(&LLPanelClassifiedEdit::onTexturePickerMouseLeave, this, edit_icon)); edit_icon->setVisible(false); LLLineEditor* line_edit = getChild("classified_name"); @@ -1130,6 +1127,7 @@ void LLPanelClassifiedEdit::onTexturePickerMouseLeave(LLUICtrl* ctrl) void LLPanelClassifiedEdit::onTextureSelected() { setSnapshotId(mSnapshotCtrl->getValue().asUUID()); + onChange(); } ////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 5e6a44c09d..392bacb8d9 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -1437,6 +1437,11 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) mColorSwatch->setFallbackImage(LLUI::getUIImage("locked_image.j2c") ); mColorSwatch->setValid(FALSE); } + LLRadioGroup* radio_mat_type = getChild("radio_material_type"); + if (radio_mat_type) + { + radio_mat_type->setSelectedIndex(0); + } getChildView("color trans")->setEnabled(FALSE); getChildView("rptctrl")->setEnabled(FALSE); getChildView("tex gen")->setEnabled(FALSE); diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp index f85a2ffbc1..b53cd222e7 100644 --- a/indra/newview/llpanelgroupgeneral.cpp +++ b/indra/newview/llpanelgroupgeneral.cpp @@ -461,11 +461,12 @@ bool LLPanelGroupGeneral::createGroupCallback(const LLSD& notification, const LL // Yay! We are making a new group! U32 enrollment_fee = (mCtrlEnrollmentFee->get() ? (U32) mSpinEnrollmentFee->get() : 0); - + LLUUID insignia_id = mInsignia->getImageItemID().isNull() ? LLUUID::null : mInsignia->getImageAssetID(); + LLGroupMgr::getInstance()->sendCreateGroupRequest(mGroupNameEditor->getText(), mEditCharter->getText(), mCtrlShowInGroupList->get(), - mInsignia->getImageAssetID(), + insignia_id, enrollment_fee, mCtrlOpenEnrollment->get(), false, diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 1cbff37287..617ca05281 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -67,6 +67,7 @@ #include "llrecentpeople.h" #include "llviewercontrol.h" // for gSavedSettings #include "llviewermenu.h" // for gMenuHolder +#include "llviewerregion.h" #include "llvoiceclient.h" #include "llworld.h" #include "llspeakers.h" @@ -613,12 +614,23 @@ void LLPanelPeople::removePicker() BOOL LLPanelPeople::postBuild() { + S32 max_premium = PREMIUM_MAX_AGENT_GROUPS; + if (gAgent.getRegion()) + { + LLSD features; + gAgent.getRegion()->getSimulatorFeatures(features); + if (features.has("MaxAgentGroupsPremium")) + { + max_premium = features["MaxAgentGroupsPremium"].asInteger(); + } + } + getChild("nearby_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); getChild("friends_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); getChild("groups_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); getChild("recent_filter_input")->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); - if(gMaxAgentGroups <= BASE_MAX_AGENT_GROUPS) + if(gMaxAgentGroups < max_premium) { getChild("groupcount")->setText(getString("GroupCountWithInfo")); getChild("groupcount")->setURLClickedCallback(boost::bind(&LLPanelPeople::onGroupLimitInfo, this)); @@ -1165,8 +1177,25 @@ void LLPanelPeople::onFilterEdit(const std::string& search_string) void LLPanelPeople::onGroupLimitInfo() { LLSD args; - args["MAX_BASIC"] = BASE_MAX_AGENT_GROUPS; - args["MAX_PREMIUM"] = PREMIUM_MAX_AGENT_GROUPS; + + S32 max_basic = BASE_MAX_AGENT_GROUPS; + S32 max_premium = PREMIUM_MAX_AGENT_GROUPS; + if (gAgent.getRegion()) + { + LLSD features; + gAgent.getRegion()->getSimulatorFeatures(features); + if (features.has("MaxAgentGroupsBasic")) + { + max_basic = features["MaxAgentGroupsBasic"].asInteger(); + } + if (features.has("MaxAgentGroupsPremium")) + { + max_premium = features["MaxAgentGroupsPremium"].asInteger(); + } + } + args["MAX_BASIC"] = max_basic; + args["MAX_PREMIUM"] = max_premium; + LLNotificationsUtil::add("GroupLimitInfo", args); } diff --git a/indra/newview/llsearchableui.cpp b/indra/newview/llsearchableui.cpp new file mode 100644 index 0000000000..de90896548 --- /dev/null +++ b/indra/newview/llsearchableui.cpp @@ -0,0 +1,159 @@ +/** +* @file llsearchableui.cpp +* +* $LicenseInfo:firstyear=2019&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2019, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" +#include "llsearchableui.h" + +#include "llview.h" +#include "lltabcontainer.h" +#include "llmenugl.h" + +ll::prefs::SearchableItem::~SearchableItem() +{} + +void ll::prefs::SearchableItem::setNotHighlighted() +{ + mCtrl->setHighlighted( false ); +} + +bool ll::prefs::SearchableItem::hightlightAndHide( LLWString const &aFilter ) +{ + if( mCtrl->getHighlighted() ) + return true; + + LLView const *pView = dynamic_cast< LLView const* >( mCtrl ); + if( pView && !pView->getVisible() ) + return false; + + if( aFilter.empty() ) + { + mCtrl->setHighlighted( false ); + return true; + } + + if( mLabel.find( aFilter ) != LLWString::npos ) + { + mCtrl->setHighlighted( true ); + return true; + } + + return false; +} + +ll::prefs::PanelData::~PanelData() +{} + +bool ll::prefs::PanelData::hightlightAndHide( LLWString const &aFilter ) +{ + for( tSearchableItemList::iterator itr = mChildren.begin(); itr != mChildren.end(); ++itr ) + (*itr)->setNotHighlighted( ); + + if (aFilter.empty()) + { + return true; + } + + bool bVisible(false); + for( tSearchableItemList::iterator itr = mChildren.begin(); itr != mChildren.end(); ++itr ) + bVisible |= (*itr)->hightlightAndHide( aFilter ); + + for( tPanelDataList::iterator itr = mChildPanel.begin(); itr != mChildPanel.end(); ++itr ) + bVisible |= (*itr)->hightlightAndHide( aFilter ); + + return bVisible; +} + +bool ll::prefs::TabContainerData::hightlightAndHide( LLWString const &aFilter ) +{ + for( tSearchableItemList::iterator itr = mChildren.begin(); itr != mChildren.end(); ++itr ) + (*itr)->setNotHighlighted( ); + + bool bVisible(false); + for( tSearchableItemList::iterator itr = mChildren.begin(); itr != mChildren.end(); ++itr ) + bVisible |= (*itr)->hightlightAndHide( aFilter ); + + for( tPanelDataList::iterator itr = mChildPanel.begin(); itr != mChildPanel.end(); ++itr ) + { + bool bPanelVisible = (*itr)->hightlightAndHide( aFilter ); + if( (*itr)->mPanel ) + mTabContainer->setTabVisibility( (*itr)->mPanel, bPanelVisible ); + bVisible |= bPanelVisible; + } + + return bVisible; +} + +ll::statusbar::SearchableItem::SearchableItem() + : mMenu(0) + , mCtrl(0) + , mWasHiddenBySearch( false ) +{ } + +void ll::statusbar::SearchableItem::setNotHighlighted( ) +{ + for( tSearchableItemList::iterator itr = mChildren.begin(); itr != mChildren.end(); ++itr ) + (*itr)->setNotHighlighted( ); + + if( mCtrl ) + { + mCtrl->setHighlighted( false ); + + if( mWasHiddenBySearch ) + mMenu->setVisible( TRUE ); + } +} + +bool ll::statusbar::SearchableItem::hightlightAndHide( LLWString const &aFilter ) +{ + if( mMenu && !mMenu->getVisible() && !mWasHiddenBySearch ) + return false; + + setNotHighlighted( ); + + bool bVisible(false); + for( tSearchableItemList::iterator itr = mChildren.begin(); itr != mChildren.end(); ++itr ) + bVisible |= (*itr)->hightlightAndHide( aFilter ); + + if( aFilter.empty() ) + { + if( mCtrl ) + mCtrl->setHighlighted( false ); + return true; + } + + if( mLabel.find( aFilter ) != LLWString::npos ) + { + if( mCtrl ) + mCtrl->setHighlighted( true ); + return true; + } + + if( mCtrl && !bVisible ) + { + mWasHiddenBySearch = true; + mMenu->setVisible(FALSE); + } + return bVisible; +} diff --git a/indra/newview/llsearchableui.h b/indra/newview/llsearchableui.h new file mode 100644 index 0000000000..42b2866fb6 --- /dev/null +++ b/indra/newview/llsearchableui.h @@ -0,0 +1,121 @@ +/** +* @file llsearchableui.h +* +* $LicenseInfo:firstyear=2019&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2019, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#ifndef LL_SEARCHABLE_UI_H +#define LL_SEARCHABLE_UI_H + +class LLMenuItemGL; +class LLView; +class LLPanel; +class LLTabContainer; + +#include "llsearchablecontrol.h" + +namespace ll +{ + namespace prefs + { + struct SearchableItem; + struct PanelData; + struct TabContainerData; + + typedef boost::shared_ptr< SearchableItem > SearchableItemPtr; + typedef boost::shared_ptr< PanelData > PanelDataPtr; + typedef boost::shared_ptr< TabContainerData > TabContainerDataPtr; + + typedef std::vector< TabContainerData > tTabContainerDataList; + typedef std::vector< SearchableItemPtr > tSearchableItemList; + typedef std::vector< PanelDataPtr > tPanelDataList; + + struct SearchableItem + { + LLWString mLabel; + LLView const *mView; + ll::ui::SearchableControl const *mCtrl; + + std::vector< boost::shared_ptr< SearchableItem > > mChildren; + + virtual ~SearchableItem(); + + void setNotHighlighted(); + virtual bool hightlightAndHide( LLWString const &aFilter ); + }; + + struct PanelData + { + LLPanel const *mPanel; + std::string mLabel; + + std::vector< boost::shared_ptr< SearchableItem > > mChildren; + std::vector< boost::shared_ptr< PanelData > > mChildPanel; + + virtual ~PanelData(); + + virtual bool hightlightAndHide( LLWString const &aFilter ); + }; + + struct TabContainerData: public PanelData + { + LLTabContainer *mTabContainer; + virtual bool hightlightAndHide( LLWString const &aFilter ); + }; + + struct SearchData + { + TabContainerDataPtr mRootTab; + LLWString mLastFilter; + }; + } + namespace statusbar + { + struct SearchableItem; + + typedef boost::shared_ptr< SearchableItem > SearchableItemPtr; + + typedef std::vector< SearchableItemPtr > tSearchableItemList; + + struct SearchableItem + { + LLWString mLabel; + LLMenuItemGL *mMenu; + tSearchableItemList mChildren; + ll::ui::SearchableControl const *mCtrl; + bool mWasHiddenBySearch; + + SearchableItem(); + + void setNotHighlighted( ); + bool hightlightAndHide( LLWString const &aFilter ); + }; + + struct SearchData + { + SearchableItemPtr mRootMenu; + LLWString mLastFilter; + }; + } +} + +#endif diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index 398ec953d7..efc57ced34 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -82,6 +82,8 @@ #include "llparcel.h" #include "llstring.h" #include "message.h" +#include "llsearchableui.h" +#include "llsearcheditor.h" // system includes #include @@ -114,7 +116,9 @@ LLStatusBar::LLStatusBar(const LLRect& rect) mBalance(0), mHealth(100), mSquareMetersCredit(0), - mSquareMetersCommitted(0) + mSquareMetersCommitted(0), + mFilterEdit(NULL), // Edit for filtering + mSearchPanel(NULL) // Panel for filtering { setRect(rect); @@ -248,6 +252,16 @@ BOOL LLStatusBar::postBuild() mPanelNearByMedia->setFollows(FOLLOWS_TOP|FOLLOWS_RIGHT); mPanelNearByMedia->setVisible(FALSE); + // Hook up and init for filtering + mFilterEdit = getChild( "search_menu_edit" ); + mSearchPanel = getChild( "menu_search_panel" ); + + mSearchPanel->setVisible(gSavedSettings.getBOOL("MenuSearch")); + mFilterEdit->setKeystrokeCallback(boost::bind(&LLStatusBar::onUpdateFilterTerm, this)); + mFilterEdit->setCommitCallback(boost::bind(&LLStatusBar::onUpdateFilterTerm, this)); + collectSearchableItems(); + gSavedSettings.getControl("MenuSearch")->getCommitSignal()->connect(boost::bind(&LLStatusBar::updateMenuSearchVisibility, this, _2)); + return TRUE; } @@ -327,6 +341,7 @@ void LLStatusBar::setVisibleForMouselook(bool visible) mMediaToggle->setVisible(visible); mSGBandwidth->setVisible(visible); mSGPacketLoss->setVisible(visible); + mSearchPanel->setVisible(visible && gSavedSettings.getBOOL("MenuSearch")); setBackgroundVisible(visible); mIconPresetsCamera->setVisible(visible); mIconPresetsGraphic->setVisible(visible); @@ -368,6 +383,12 @@ void LLStatusBar::setBalance(S32 balance) balance_bg_view->setShape(balance_bg_rect); } + // If the search panel is shown, move this according to the new balance width. Parcel text will reshape itself in setParcelInfoText + if (mSearchPanel && mSearchPanel->getVisible()) + { + updateMenuSearchPosition(); + } + if (mBalance && (fabs((F32)(mBalance - balance)) > gSavedSettings.getF32("UISndMoneyChangeThreshold"))) { if (mBalance > balance) @@ -606,6 +627,75 @@ void LLStatusBar::onVolumeChanged(const LLSD& newvalue) refresh(); } +void LLStatusBar::onUpdateFilterTerm() +{ + LLWString searchValue = utf8str_to_wstring( mFilterEdit->getValue() ); + LLWStringUtil::toLower( searchValue ); + + if( !mSearchData || mSearchData->mLastFilter == searchValue ) + return; + + mSearchData->mLastFilter = searchValue; + + mSearchData->mRootMenu->hightlightAndHide( searchValue ); + gMenuBarView->needsArrange(); +} + +void collectChildren( LLMenuGL *aMenu, ll::statusbar::SearchableItemPtr aParentMenu ) +{ + for( U32 i = 0; i < aMenu->getItemCount(); ++i ) + { + LLMenuItemGL *pMenu = aMenu->getItem( i ); + + ll::statusbar::SearchableItemPtr pItem( new ll::statusbar::SearchableItem ); + pItem->mCtrl = pMenu; + pItem->mMenu = pMenu; + pItem->mLabel = utf8str_to_wstring( pMenu->ll::ui::SearchableControl::getSearchText() ); + LLWStringUtil::toLower( pItem->mLabel ); + aParentMenu->mChildren.push_back( pItem ); + + LLMenuItemBranchGL *pBranch = dynamic_cast< LLMenuItemBranchGL* >( pMenu ); + if( pBranch ) + collectChildren( pBranch->getBranch(), pItem ); + } + +} + +void LLStatusBar::collectSearchableItems() +{ + mSearchData.reset( new ll::statusbar::SearchData ); + ll::statusbar::SearchableItemPtr pItem( new ll::statusbar::SearchableItem ); + mSearchData->mRootMenu = pItem; + collectChildren( gMenuBarView, pItem ); +} + +void LLStatusBar::updateMenuSearchVisibility(const LLSD& data) +{ + bool visible = data.asBoolean(); + mSearchPanel->setVisible(visible); + if (!visible) + { + mFilterEdit->setText(LLStringUtil::null); + onUpdateFilterTerm(); + } + else + { + updateMenuSearchPosition(); + } +} + +void LLStatusBar::updateMenuSearchPosition() +{ + const S32 HPAD = 12; + LLRect balanceRect = getChildView("balance_bg")->getRect(); + LLRect searchRect = mSearchPanel->getRect(); + S32 w = searchRect.getWidth(); + searchRect.mLeft = balanceRect.mLeft - w - HPAD; + searchRect.mRight = searchRect.mLeft + w; + mSearchPanel->setShape( searchRect ); +} + + // Implements secondlife:///app/balance/request to request a L$ balance // update via UDP message system. JC class LLBalanceHandler : public LLCommandHandler diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h index 040b7bc949..381ac1773f 100644 --- a/indra/newview/llstatusbar.h +++ b/indra/newview/llstatusbar.h @@ -46,7 +46,15 @@ class LLPanelPresetsPulldown; class LLPanelVolumePulldown; class LLPanelNearByMedia; class LLIconCtrl; +class LLSearchEditor; +namespace ll +{ + namespace statusbar + { + struct SearchData; + } +} class LLStatusBar : public LLPanel { @@ -101,6 +109,15 @@ private: static void onClickMediaToggle(void* data); static void onClickBalance(void* data); + LLSearchEditor *mFilterEdit; + LLPanel *mSearchPanel; + void onUpdateFilterTerm(); + + std::unique_ptr< ll::statusbar::SearchData > mSearchData; + void collectSearchableItems(); + void updateMenuSearchVisibility( const LLSD& data ); + void updateMenuSearchPosition(); + private: LLTextBox *mTextTime; diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 633e025478..e5af47ab6c 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -825,10 +825,10 @@ void LLTextureCacheWorker::endWork(S32 param, bool aborted) LLTextureCache::LLTextureCache(bool threaded) : LLWorkerThread("TextureCache", threaded), - mWorkersMutex(NULL), - mHeaderMutex(NULL), - mListMutex(NULL), - mFastCacheMutex(NULL), + mWorkersMutex(), + mHeaderMutex(), + mListMutex(), + mFastCacheMutex(), mHeaderAPRFile(NULL), mReadOnly(TRUE), //do not allow to change the texture cache until setReadOnly() is called. mTexturesSizeTotal(0), @@ -1038,11 +1038,11 @@ S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL texture_cache { llassert_always(getPending() == 0) ; //should not start accessing the texture cache before initialized. - S64 header_size = (max_size / 100) * 36; //0.36 * max_size - S64 max_entries = header_size / (TEXTURE_CACHE_ENTRY_SIZE + TEXTURE_FAST_CACHE_ENTRY_SIZE); + S64 entries_size = (max_size * 36) / 100; //0.36 * max_size + S64 max_entries = entries_size / (TEXTURE_CACHE_ENTRY_SIZE + TEXTURE_FAST_CACHE_ENTRY_SIZE); sCacheMaxEntries = (S32)(llmin((S64)sCacheMaxEntries, max_entries)); - header_size = sCacheMaxEntries * TEXTURE_CACHE_ENTRY_SIZE; - max_size -= header_size; + entries_size = sCacheMaxEntries * (TEXTURE_CACHE_ENTRY_SIZE + TEXTURE_FAST_CACHE_ENTRY_SIZE); + max_size -= entries_size; if (sCacheMaxTexturesSize > 0) sCacheMaxTexturesSize = llmin(sCacheMaxTexturesSize, max_size); else diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h index 987b9375c0..81ea7aeee2 100644 --- a/indra/newview/lltexturecache.h +++ b/indra/newview/lltexturecache.h @@ -221,7 +221,7 @@ private: typedef std::map size_map_t; size_map_t mTexturesSizeMap; S64 mTexturesSizeTotal; - LLAtomic32 mDoPurge; + LLAtomicBool mDoPurge; typedef std::map idx_entry_map_t; idx_entry_map_t mUpdatedEntryMap; diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index a5a2eec246..1396a8546d 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -131,7 +131,7 @@ LLFloaterTexturePicker::~LLFloaterTexturePicker() void LLFloaterTexturePicker::setImageID(const LLUUID& image_id, bool set_selection /*=true*/) { - if( mImageAssetID != image_id && mActive) + if( ((mImageAssetID != image_id) || mTentative) && mActive) { mNoCopyTextureSelected = FALSE; mViewModel->setDirty(); // *TODO: shouldn't we be using setValue() here? @@ -1096,6 +1096,10 @@ void LLTextureCtrl::setVisible( BOOL visible ) void LLTextureCtrl::setEnabled( BOOL enabled ) { LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterHandle.get(); + if( floaterp ) + { + floaterp->setActive(enabled); + } if( enabled ) { std::string tooltip; @@ -1110,11 +1114,6 @@ void LLTextureCtrl::setEnabled( BOOL enabled ) closeDependentFloater(); } - if( floaterp ) - { - floaterp->setActive(enabled); - } - mCaption->setEnabled( enabled ); LLView::setEnabled( enabled ); @@ -1215,9 +1214,10 @@ void LLTextureCtrl::showPicker(BOOL take_focus) void LLTextureCtrl::closeDependentFloater() { LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterHandle.get(); - if( floaterp ) + if( floaterp && floaterp->isInVisibleChain()) { floaterp->setOwner(NULL); + floaterp->setVisible(FALSE); floaterp->closeFloater(); } } diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index f8849bf997..c9133338fb 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -936,7 +936,7 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher, mCanUseHTTP(true), mRetryAttempt(0), mActiveCount(0), - mWorkMutex(NULL), + mWorkMutex(), mFirstPacket(0), mLastPacket(-1), mTotalPackets(0), @@ -2558,8 +2558,8 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image mDebugPause(FALSE), mPacketCount(0), mBadPacketCount(0), - mQueueMutex(getAPRPool()), - mNetworkQueueMutex(getAPRPool()), + mQueueMutex(), + mNetworkQueueMutex(), mTextureCache(cache), mImageDecodeThread(imagedecodethread), mTextureBandwidth(0), diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index a2155bde1f..a01c01847e 100644 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -35,7 +35,6 @@ #include "lluuid.h" #include "llworkerthread.h" #include "lltextureinfo.h" -#include "llapr.h" #include "llimageworker.h" #include "httprequest.h" #include "httpoptions.h" diff --git a/indra/newview/lltoastgroupnotifypanel.cpp b/indra/newview/lltoastgroupnotifypanel.cpp index f7dc32d0d7..817d1dd7b4 100644 --- a/indra/newview/lltoastgroupnotifypanel.cpp +++ b/indra/newview/lltoastgroupnotifypanel.cpp @@ -84,14 +84,14 @@ LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(const LLNotificationPtr& notifi //message body const std::string& message = payload["message"].asString(); - std::string timeStr = "["+LLTrans::getString("UTCTimeWeek")+"],[" - +LLTrans::getString("UTCTimeDay")+"] [" - +LLTrans::getString("UTCTimeMth")+"] [" - +LLTrans::getString("UTCTimeYr")+"] [" - +LLTrans::getString("UTCTimeHr")+"]:[" - +LLTrans::getString("UTCTimeMin")+"]:[" - +LLTrans::getString("UTCTimeSec")+"] [" - +LLTrans::getString("UTCTimeTimezone")+"]"; + std::string timeStr = "[" + LLTrans::getString("TimeWeek") + "], [" + + LLTrans::getString("TimeMonth") + "]/[" + + LLTrans::getString("TimeDay") + "]/[" + + LLTrans::getString("TimeYear") + "] [" + + LLTrans::getString("TimeHour") + "]:[" + + LLTrans::getString("TimeMin") + "] [" + + LLTrans::getString("TimeTimezone") + "]"; + const LLDate timeStamp = notification->getDate(); LLDate notice_date = timeStamp.notNull() ? timeStamp : payload["received_time"].asDate(); LLSD substitution; diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp index e3a856be5c..a2116817a2 100644 --- a/indra/newview/lltoastnotifypanel.cpp +++ b/indra/newview/lltoastnotifypanel.cpp @@ -46,8 +46,6 @@ const S32 BOTTOM_PAD = VPAD * 3; const S32 IGNORE_BTN_TOP_DELTA = 3*VPAD;//additional ignore_btn padding S32 BUTTON_WIDTH = 90; -// *TODO: magic numbers - copied from llnotify.cpp(250) -const S32 MAX_LENGTH = 512 + 20 + DB_FIRST_NAME_BUF_SIZE + DB_LAST_NAME_BUF_SIZE + DB_INV_ITEM_NAME_BUF_SIZE; //static @@ -319,7 +317,7 @@ void LLToastNotifyPanel::init( LLRect rect, bool show_images ) mTextBox = getChild("text_editor_box"); } - mTextBox->setMaxTextLength(MAX_LENGTH); + mTextBox->setMaxTextLength(LLToastPanel::MAX_TEXT_LENGTH); mTextBox->setVisible(TRUE); mTextBox->setPlainText(!show_images); mTextBox->setContentTrusted(is_content_trusted); @@ -411,7 +409,7 @@ void LLToastNotifyPanel::init( LLRect rect, bool show_images ) //.xml file intially makes info panel only follow left/right/top. This is so that when control buttons are added the info panel //can shift upward making room for the buttons inside mControlPanel. After the buttons are added, the info panel can then be set to follow 'all'. mInfoPanel->setFollowsAll(); - snapToMessageHeight(mTextBox, MAX_LENGTH); + snapToMessageHeight(mTextBox, LLToastPanel::MAX_TEXT_LENGTH); // reshape the panel to its previous size if (current_rect.notEmpty()) @@ -472,7 +470,7 @@ void LLIMToastNotifyPanel::snapToMessageHeight() //Add message height if it is visible if (mTextBox->getVisible()) { - S32 new_panel_height = computeSnappedToMessageHeight(mTextBox, MAX_LENGTH); + S32 new_panel_height = computeSnappedToMessageHeight(mTextBox, LLToastPanel::MAX_TEXT_LENGTH); //reshape the panel with new height if (new_panel_height != getRect().getHeight()) diff --git a/indra/newview/lltoastpanel.cpp b/indra/newview/lltoastpanel.cpp index e1b764a943..7c624d5b50 100644 --- a/indra/newview/lltoastpanel.cpp +++ b/indra/newview/lltoastpanel.cpp @@ -26,6 +26,7 @@ #include "llviewerprecompiledheaders.h" +#include "lldbstrings.h" #include "llpanelgenerictip.h" #include "llpanelonlinestatus.h" #include "llnotifications.h" @@ -35,6 +36,8 @@ //static const S32 LLToastPanel::MIN_PANEL_HEIGHT = 40; // VPAD(4)*2 + ICON_HEIGHT(32) +// 'magic numbers', consider initializing (512+20) part from xml/notifications +const S32 LLToastPanel::MAX_TEXT_LENGTH = 512 + 20 + DB_FIRST_NAME_BUF_SIZE + DB_LAST_NAME_BUF_SIZE + DB_INV_ITEM_NAME_BUF_SIZE; LLToastPanel::LLToastPanel(const LLNotificationPtr& notification) { diff --git a/indra/newview/lltoastpanel.h b/indra/newview/lltoastpanel.h index 51630381f2..6a9b72a5ae 100644 --- a/indra/newview/lltoastpanel.h +++ b/indra/newview/lltoastpanel.h @@ -49,6 +49,7 @@ public: virtual const LLUUID& getID(); static const S32 MIN_PANEL_HEIGHT; + static const S32 MAX_TEXT_LENGTH; /** * Builder method for constructing notification specific panels. diff --git a/indra/newview/lltoastscripttextbox.cpp b/indra/newview/lltoastscripttextbox.cpp index 518c6c0ee4..eb86a44055 100644 --- a/indra/newview/lltoastscripttextbox.cpp +++ b/indra/newview/lltoastscripttextbox.cpp @@ -36,8 +36,6 @@ #include "llviewertexteditor.h" const S32 LLToastScriptTextbox::DEFAULT_MESSAGE_MAX_LINE_COUNT= 14; -// *TODO: magic numbers - copied from lltoastnotifypanel.cpp(50) which was copied from llnotify.cpp(250) -const S32 MAX_LENGTH = 512 + 20 + DB_FIRST_NAME_BUF_SIZE + DB_LAST_NAME_BUF_SIZE + DB_INV_ITEM_NAME_BUF_SIZE; LLToastScriptTextbox::LLToastScriptTextbox(const LLNotificationPtr& notification) : LLToastPanel(notification) @@ -45,7 +43,7 @@ LLToastScriptTextbox::LLToastScriptTextbox(const LLNotificationPtr& notification buildFromFile( "panel_notify_textbox.xml"); mInfoText = getChild("text_editor_box"); - mInfoText->setMaxTextLength(MAX_LENGTH); + mInfoText->setMaxTextLength(LLToastPanel::MAX_TEXT_LENGTH); mInfoText->setValue(notification->getMessage()); getChild("ignore_btn")->setClickedCallback(boost::bind(&LLToastScriptTextbox::onClickIgnore, this)); diff --git a/indra/newview/lltool.cpp b/indra/newview/lltool.cpp index 4aad650b68..b5d78f3654 100644 --- a/indra/newview/lltool.cpp +++ b/indra/newview/lltool.cpp @@ -191,7 +191,9 @@ LLTool* LLTool::getOverrideTool(MASK mask) { return NULL; } - if (gSavedSettings.getBOOL("EnableAltZoom")) + + static LLCachedControl alt_zoom(gSavedSettings, "EnableAltZoom", true); + if (alt_zoom) { if (mask & MASK_ALT) { diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 9e37ca0394..697db01d11 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -111,11 +111,24 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask) mMouseOutsideSlop = FALSE; mMouseDownX = x; mMouseDownY = y; - LLTimer pick_timer; - BOOL pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"); - //left mouse down always picks transparent (but see handleMouseUp) - mPick = gViewerWindow->pickImmediate(x, y, TRUE, pick_rigged); - LL_INFOS() << "pick_rigged is " << (S32) pick_rigged << " pick time elapsed " << pick_timer.getElapsedTimeF32() << LL_ENDL; + LLTimer pick_timer; + BOOL pick_rigged = false; //gSavedSettings.getBOOL("AnimatedObjectsAllowLeftClick"); + mPick = gViewerWindow->pickImmediate(x, y, FALSE, pick_rigged); + LLViewerObject *object = mPick.getObject(); + LLViewerObject *parent = object ? object->getRootEdit() : NULL; + if (!object + || object->isAttachment() + || object->getClickAction() == CLICK_ACTION_DISABLED + || (!useClickAction(mask, object, parent) && !object->flagHandleTouch() && !(parent && parent->flagHandleTouch()))) + { + // Unless we are hovering over actionable visible object + // left mouse down always picks transparent (but see handleMouseUp). + // Also see LLToolPie::handleHover() - priorities are a bit different there. + // Todo: we need a more consistent set of rules to work with + mPick = gViewerWindow->pickImmediate(x, y, TRUE /*transparent*/, pick_rigged); + } + LL_INFOS() << "pick_rigged is " << (S32) pick_rigged << " pick time elapsed " << pick_timer.getElapsedTimeF32() << LL_ENDL; + mPick.mKeyMask = mask; mMouseButtonDown = true; @@ -857,13 +870,11 @@ static bool needs_tooltip(LLSelectNode* nodep) BOOL LLToolPie::handleTooltipLand(std::string line, std::string tooltip_msg) { - LLViewerParcelMgr::getInstance()->setHoverParcel( mHoverPick.mPosGlobal ); - // - // Do not show hover for land unless prefs are set to allow it. - // - + // Do not show hover for land unless prefs are set to allow it. if (!gSavedSettings.getBOOL("ShowLandHoverTip")) return TRUE; - + + LLViewerParcelMgr::getInstance()->setHoverParcel( mHoverPick.mPosGlobal ); + // Didn't hit an object, but since we have a land point we // must be hovering over land. diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 88984d518a..a699491e1b 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -219,20 +219,20 @@ static bool handleAnisotropicChanged(const LLSD& newvalue) static bool handleVolumeLODChanged(const LLSD& newvalue) { - LLVOVolume::sLODFactor = (F32) newvalue.asReal(); + LLVOVolume::sLODFactor = llclamp((F32) newvalue.asReal(), 0.01f, MAX_LOD_FACTOR); LLVOVolume::sDistanceFactor = 1.f-LLVOVolume::sLODFactor * 0.1f; return true; } static bool handleAvatarLODChanged(const LLSD& newvalue) { - LLVOAvatar::sLODFactor = (F32) newvalue.asReal(); + LLVOAvatar::sLODFactor = llclamp((F32) newvalue.asReal(), 0.f, MAX_AVATAR_LOD_FACTOR); return true; } static bool handleAvatarPhysicsLODChanged(const LLSD& newvalue) { - LLVOAvatar::sPhysicsLODFactor = (F32) newvalue.asReal(); + LLVOAvatar::sPhysicsLODFactor = llclamp((F32) newvalue.asReal(), 0.f, MAX_AVATAR_LOD_FACTOR); return true; } diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 11d14def22..f4db81c826 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -91,6 +91,7 @@ #include "llfloatermediasettings.h" #include "llfloatermemleak.h" #include "llfloatermodelpreview.h" +#include "llfloatermyscripts.h" #include "llfloaternamedesc.h" #include "llfloaternotificationsconsole.h" #include "llfloaternotificationstabbed.h" @@ -339,6 +340,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("script_debug_output", "floater_script_debug_panel.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("script_floater", "floater_script.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("script_limits", "floater_script_limits.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("my_scripts", "floater_my_scripts.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("sell_land", "floater_sell_land.xml", &LLFloaterSellLand::buildFloater); LLFloaterReg::add("settings_debug", "floater_settings_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("sound_devices", "floater_sound_devices.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 22a21c9ca3..d8745b1eca 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -682,8 +682,8 @@ void LLViewerMedia::updateMedia(void *dummy_arg) std::vector proximity_order; - bool inworld_media_enabled = gSavedSettings.getBOOL("AudioStreamingMedia"); - bool inworld_audio_enabled = gSavedSettings.getBOOL("AudioStreamingMusic"); + static LLCachedControl inworld_media_enabled(gSavedSettings, "AudioStreamingMedia", true); + static LLCachedControl inworld_audio_enabled(gSavedSettings, "AudioStreamingMusic", true); U32 max_instances = gSavedSettings.getU32("PluginInstancesTotal"); U32 max_normal = gSavedSettings.getU32("PluginInstancesNormal"); U32 max_low = gSavedSettings.getU32("PluginInstancesLow"); @@ -941,7 +941,8 @@ void LLViewerMedia::setAllMediaEnabled(bool val) LLViewerParcelMedia::play(LLViewerParcelMgr::getInstance()->getAgentParcel()); } - if (gSavedSettings.getBOOL("AudioStreamingMusic") && + static LLCachedControl audio_streaming_music(gSavedSettings, "AudioStreamingMusic", true); + if (audio_streaming_music && !LLViewerMedia::isParcelAudioPlaying() && gAudiop && LLViewerMedia::hasParcelAudio()) @@ -1012,7 +1013,8 @@ void LLViewerMedia::setAllMediaPaused(bool val) LLViewerParcelMedia::play(LLViewerParcelMgr::getInstance()->getAgentParcel()); } - if (gSavedSettings.getBOOL("AudioStreamingMusic") && + static LLCachedControl audio_streaming_music(gSavedSettings, "AudioStreamingMusic", true); + if (audio_streaming_music && !LLViewerMedia::isParcelAudioPlaying() && gAudiop && LLViewerMedia::hasParcelAudio()) @@ -3318,8 +3320,39 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla } else { - // Don't track redirects. - setNavState(MEDIANAVSTATE_NONE); + bool internal_nav = false; + if (url != mCurrentMediaURL) + { + // Check if it is internal navigation + // Note: Not sure if we should detect internal navigations as 'address change', + // but they are not redirects and do not cause NAVIGATE_BEGIN (also see SL-1005) + size_t pos = url.find("#"); + if (pos != std::string::npos) + { + // assume that new link always have '#', so this is either + // transfer from 'link#1' to 'link#2' or from link to 'link#2' + // filter out cases like 'redirect?link' + std::string base_url = url.substr(0, pos); + pos = mCurrentMediaURL.find(base_url); + if (pos == 0) + { + // base link hasn't changed + internal_nav = true; + } + } + } + + if (internal_nav) + { + // Internal navigation by '#' + mCurrentMediaURL = url; + setNavState(MEDIANAVSTATE_FIRST_LOCATION_CHANGED); + } + else + { + // Don't track redirects. + setNavState(MEDIANAVSTATE_NONE); + } } } break; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 6c52f118ad..ba68ce4cf4 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -7068,6 +7068,10 @@ BOOL object_selected_and_point_valid() BOOL object_is_wearable() { + if (!isAgentAvatarValid()) + { + return FALSE; + } if (!object_selected_and_point_valid()) { return FALSE; @@ -7076,17 +7080,7 @@ BOOL object_is_wearable() { return FALSE; } - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin(); - iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++) - { - LLSelectNode* node = *iter; - if (node->mPermissions->getOwner() == gAgent.getID()) - { - return TRUE; - } - } - return FALSE; + return gAgentAvatarp->canAttachMoreObjects(); } @@ -9207,7 +9201,7 @@ void initialize_menus() enable.add("Object.EnableOpen", boost::bind(&enable_object_open)); enable.add("Object.EnableTouch", boost::bind(&enable_object_touch, _1)); enable.add("Object.EnableDelete", boost::bind(&enable_object_delete)); - enable.add("Object.EnableWear", boost::bind(&object_selected_and_point_valid)); + enable.add("Object.EnableWear", boost::bind(&object_is_wearable)); enable.add("Object.EnableStandUp", boost::bind(&enable_object_stand_up)); enable.add("Object.EnableSit", boost::bind(&enable_object_sit, _1)); diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index d2a5578568..a9a91b158b 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -175,7 +175,7 @@ void LLFilePickerThread::run() //static void LLFilePickerThread::initClass() { - sMutex = new LLMutex(NULL); + sMutex = new LLMutex(); } //static diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 981d226824..e50c8ee9f0 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -5531,17 +5531,6 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp void script_question_mute(const LLUUID& item_id, const std::string& object_name); -bool unknown_script_question_cb(const LLSD& notification, const LLSD& response) -{ - // Only care if they muted the object here. - if ( response["Mute"] ) // mute - { - LLUUID task_id = notification["payload"]["task_id"].asUUID(); - script_question_mute(task_id,notification["payload"]["object_name"].asString()); - } - return false; -} - void experiencePermissionBlock(LLUUID experience, LLSD result) { LLSD permission; @@ -5647,8 +5636,7 @@ void script_question_mute(const LLUUID& task_id, const std::string& object_name) bool matches(const LLNotificationPtr notification) const { if (notification->getName() == "ScriptQuestionCaution" - || notification->getName() == "ScriptQuestion" - || notification->getName() == "UnknownScriptQuestion") + || notification->getName() == "ScriptQuestion") { return (notification->getPayload()["task_id"].asUUID() == blocked_id); } @@ -5665,7 +5653,6 @@ void script_question_mute(const LLUUID& task_id, const std::string& object_name) static LLNotificationFunctorRegistration script_question_cb_reg_1("ScriptQuestion", script_question_cb); static LLNotificationFunctorRegistration script_question_cb_reg_2("ScriptQuestionCaution", script_question_cb); static LLNotificationFunctorRegistration script_question_cb_reg_3("ScriptQuestionExperience", script_question_cb); -static LLNotificationFunctorRegistration unknown_script_question_cb_reg("UnknownScriptQuestion", unknown_script_question_cb); void process_script_experience_details(const LLSD& experience_details, LLSD args, LLSD payload) { @@ -5778,14 +5765,12 @@ void process_script_question(LLMessageSystem *msg, void **user_data) args["QUESTIONS"] = script_question; if (known_questions != questions) - { // This is in addition to the normal dialog. - LLSD payload; - payload["task_id"] = taskid; - payload["item_id"] = itemid; - payload["object_name"] = object_name; - - args["DOWNLOADURL"] = LLTrans::getString("ViewerDownloadURL"); - LLNotificationsUtil::add("UnknownScriptQuestion",args,payload); + { + // This is in addition to the normal dialog. + // Viewer got a request for not supported/implemented permission + LL_WARNS("Messaging") << "Object \"" << object_name << "\" requested " << script_question + << " permission. Permission is unknown and can't be granted. Item id: " << itemid + << " taskid:" << taskid << LL_ENDL; } if (known_questions) diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 226283e1b2..ec1095813b 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -127,6 +127,7 @@ BOOL LLViewerObject::sUseSharedDrawables(FALSE); // TRUE // sMaxUpdateInterpolationTime must be greater than sPhaseOutUpdateInterpolationTime F64Seconds LLViewerObject::sMaxUpdateInterpolationTime(3.0); // For motion interpolation: after X seconds with no updates, don't predict object motion F64Seconds LLViewerObject::sPhaseOutUpdateInterpolationTime(2.0); // For motion interpolation: after Y seconds with no updates, taper off motion prediction +F64Seconds LLViewerObject::sMaxRegionCrossingInterpolationTime(1.0);// For motion interpolation: don't interpolate over this time on region crossing std::map LLViewerObject::sObjectDataMap; @@ -260,6 +261,7 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe mLastInterpUpdateSecs(0.f), mLastMessageUpdateSecs(0.f), mLatestRecvPacketID(0), + mRegionCrossExpire(0), mData(NULL), mAudioSourcep(NULL), mAudioGain(1.f), @@ -2487,7 +2489,7 @@ void LLViewerObject::loadFlags(U32 flags) return; } -void LLViewerObject::idleUpdate(LLAgent &agent, const F64 &time) +void LLViewerObject::idleUpdate(LLAgent &agent, const F64 &frame_time) { //static LLTrace::BlockTimerStatHandle ftm("Viewer Object"); //LL_RECORD_BLOCK_TIME(ftm); @@ -2498,19 +2500,19 @@ void LLViewerObject::idleUpdate(LLAgent &agent, const F64 &time) { // calculate dt from last update F32 time_dilation = mRegionp ? mRegionp->getTimeDilation() : 1.0f; - F32 dt_raw = ((F64Seconds)time - mLastInterpUpdateSecs).value(); + F32 dt_raw = ((F64Seconds)frame_time - mLastInterpUpdateSecs).value(); F32 dt = time_dilation * dt_raw; applyAngularVelocity(dt); if (isAttachment()) { - mLastInterpUpdateSecs = (F64Seconds)time; + mLastInterpUpdateSecs = (F64Seconds)frame_time; return; } else { // Move object based on it's velocity and rotation - interpolateLinearMotion(time, dt); + interpolateLinearMotion(frame_time, dt); } } @@ -2520,7 +2522,7 @@ void LLViewerObject::idleUpdate(LLAgent &agent, const F64 &time) // Move an object due to idle-time viewer side updates by interpolating motion -void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, const F32SecondsImplicit& dt_seconds) +void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& frame_time, const F32SecondsImplicit& dt_seconds) { // linear motion // PHYSICS_TIMESTEP is used below to correct for the fact that the velocity in object @@ -2532,7 +2534,7 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con // zeroing it out F32 dt = dt_seconds; - F64Seconds time_since_last_update = time - mLastMessageUpdateSecs; + F64Seconds time_since_last_update = frame_time - mLastMessageUpdateSecs; if (time_since_last_update <= (F64Seconds)0.0 || dt <= 0.f) { return; @@ -2580,7 +2582,7 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con (time_since_last_packet > sPhaseOutUpdateInterpolationTime)) { // Start to reduce motion interpolation since we haven't seen a server update in a while - F64Seconds time_since_last_interpolation = time - mLastInterpUpdateSecs; + F64Seconds time_since_last_interpolation = frame_time - mLastInterpUpdateSecs; F64 phase_out = 1.0; if (time_since_last_update > sMaxUpdateInterpolationTime) { // Past the time limit, so stop the object @@ -2635,7 +2637,7 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con new_pos.mV[VZ] = llmax(min_height, new_pos.mV[VZ]); // Check to see if it's going off the region - LLVector3 temp(new_pos); + LLVector3 temp(new_pos.mV[VX], new_pos.mV[VY], 0.f); if (temp.clamp(0.f, mRegionp->getWidth())) { // Going off this region, so see if we might end up on another region LLVector3d old_pos_global = mRegionp->getPosGlobalFromRegion(getPositionRegion()); @@ -2644,21 +2646,47 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con // Clip the positions to known regions LLVector3d clip_pos_global = LLWorld::getInstance()->clipToVisibleRegions(old_pos_global, new_pos_global); if (clip_pos_global != new_pos_global) - { // Was clipped, so this means we hit a edge where there is no region to enter - - //LL_INFOS() << "Hit empty region edge, clipped predicted position to " << mRegionp->getPosRegionFromGlobal(clip_pos_global) - // << " from " << new_pos << LL_ENDL; - new_pos = mRegionp->getPosRegionFromGlobal(clip_pos_global); + { + // Was clipped, so this means we hit a edge where there is no region to enter + LLVector3 clip_pos = mRegionp->getPosRegionFromGlobal(clip_pos_global); + LL_DEBUGS("Interpolate") << "Hit empty region edge, clipped predicted position to " + << clip_pos + << " from " << new_pos << LL_ENDL; + new_pos = clip_pos; // Stop motion and get server update for bouncing on the edge new_v.clear(); setAcceleration(LLVector3::zero); } else - { // Let predicted movement cross into another region - //LL_INFOS() << "Predicting region crossing to " << new_pos << LL_ENDL; + { + // Check for how long we are crossing. + // Note: theoretically we can find time from velocity, acceleration and + // distance from border to new position, but it is not going to work + // if 'phase_out' activates + if (mRegionCrossExpire == 0) + { + // Workaround: we can't accurately figure out time when we cross border + // so just write down time 'after the fact', it is far from optimal in + // case of lags, but for lags sMaxUpdateInterpolationTime will kick in first + LL_DEBUGS("Interpolate") << "Predicted region crossing, new position " << new_pos << LL_ENDL; + mRegionCrossExpire = frame_time + sMaxRegionCrossingInterpolationTime; + } + else if (frame_time > mRegionCrossExpire) + { + // Predicting crossing over 1s, stop motion + // Stop motion + LL_DEBUGS("Interpolate") << "Predicting region crossing for too long, stopping at " << new_pos << LL_ENDL; + new_v.clear(); + setAcceleration(LLVector3::zero); + mRegionCrossExpire = 0; + } } } + else + { + mRegionCrossExpire = 0; + } // Set new position and velocity setPositionRegion(new_pos); @@ -2669,7 +2697,7 @@ void LLViewerObject::interpolateLinearMotion(const F64SecondsImplicit& time, con } // Update the last time we did anything - mLastInterpUpdateSecs = time; + mLastInterpUpdateSecs = frame_time; } diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index d6c8b76147..8b1535851e 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -615,7 +615,7 @@ private: U32 checkMediaURL(const std::string &media_url); // Motion prediction between updates - void interpolateLinearMotion(const F64SecondsImplicit & time, const F32SecondsImplicit & dt); + void interpolateLinearMotion(const F64SecondsImplicit & frame_time, const F32SecondsImplicit & dt); static void initObjectDataMap(); @@ -772,6 +772,7 @@ protected: F64Seconds mLastInterpUpdateSecs; // Last update for purposes of interpolation F64Seconds mLastMessageUpdateSecs; // Last update from a message from the simulator TPACKETID mLatestRecvPacketID; // Latest time stamp on message from simulator + F64SecondsImplicit mRegionCrossExpire; // frame time we detected region crossing in + wait time // extra data sent from the sim...currently only used for tree species info U8* mData; @@ -851,6 +852,7 @@ protected: static void setPhaseOutUpdateInterpolationTime(F32 value) { sPhaseOutUpdateInterpolationTime = (F64Seconds) value; } static void setMaxUpdateInterpolationTime(F32 value) { sMaxUpdateInterpolationTime = (F64Seconds) value; } + static void setMaxRegionCrossingInterpolationTime(F32 value) { sMaxRegionCrossingInterpolationTime = (F64Seconds) value; } static void setVelocityInterpolate(BOOL value) { sVelocityInterpolate = value; } static void setPingInterpolate(BOOL value) { sPingInterpolate = value; } @@ -860,6 +862,7 @@ private: static F64Seconds sPhaseOutUpdateInterpolationTime; // For motion interpolation static F64Seconds sMaxUpdateInterpolationTime; // For motion interpolation + static F64Seconds sMaxRegionCrossingInterpolationTime; // For motion interpolation static BOOL sVelocityInterpolate; static BOOL sPingInterpolate; diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 2aff71367e..932759c86d 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -854,6 +854,7 @@ void LLViewerObjectList::update(LLAgent &agent) F32 interp_time = gSavedSettings.getF32("InterpolationTime"); F32 phase_out_time = gSavedSettings.getF32("InterpolationPhaseOut"); + F32 region_interp_time = llclamp(gSavedSettings.getF32("RegionCrossingInterpolationTime"), 0.5f, 5.f); if (interp_time < 0.0 || phase_out_time < 0.0 || phase_out_time > interp_time) @@ -864,6 +865,7 @@ void LLViewerObjectList::update(LLAgent &agent) } LLViewerObject::setPhaseOutUpdateInterpolationTime( interp_time ); LLViewerObject::setMaxUpdateInterpolationTime( phase_out_time ); + LLViewerObject::setMaxRegionCrossingInterpolationTime(region_interp_time); gAnimateTextures = gSavedSettings.getBOOL("AnimateTextures"); diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index f4d14a39fe..416d5d8e2e 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -957,7 +957,7 @@ void LLViewerParcelMgr::sendParcelGodForceOwner(const LLUUID& owner_id) return; } - LL_INFOS() << "Claiming " << mWestSouth << " to " << mEastNorth << LL_ENDL; + LL_INFOS("ParcelMgr") << "Claiming " << mWestSouth << " to " << mEastNorth << LL_ENDL; // BUG: Only works for the region containing mWestSouthBottom LLVector3d east_north_region_check( mEastNorth ); @@ -980,7 +980,7 @@ void LLViewerParcelMgr::sendParcelGodForceOwner(const LLUUID& owner_id) return; } - LL_INFOS() << "Region " << region->getOriginGlobal() << LL_ENDL; + LL_INFOS("ParcelMgr") << "Region " << region->getOriginGlobal() << LL_ENDL; LLSD payload; payload["owner_id"] = owner_id; @@ -1120,8 +1120,8 @@ LLViewerParcelMgr::ParcelBuyInfo* LLViewerParcelMgr::setupParcelBuy( if (is_claim) { - LL_INFOS() << "Claiming " << mWestSouth << " to " << mEastNorth << LL_ENDL; - LL_INFOS() << "Region " << region->getOriginGlobal() << LL_ENDL; + LL_INFOS("ParcelMgr") << "Claiming " << mWestSouth << " to " << mEastNorth << LL_ENDL; + LL_INFOS("ParcelMgr") << "Region " << region->getOriginGlobal() << LL_ENDL; // BUG: Only works for the region containing mWestSouthBottom LLVector3d east_north_region_check( mEastNorth ); @@ -1294,8 +1294,6 @@ void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_ag if (!region) return; - //LL_INFOS() << "found region: " << region->getName() << LL_ENDL; - LLSD body; std::string url = region->getCapability("ParcelPropertiesUpdate"); if (!url.empty()) @@ -1304,7 +1302,7 @@ void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_ag U32 message_flags = 0x01; body["flags"] = ll_sd_from_U32(message_flags); parcel->packMessage(body); - LL_INFOS() << "Sending parcel properties update via capability to: " + LL_INFOS("ParcelMgr") << "Sending parcel properties update via capability to: " << url << LL_ENDL; LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body, @@ -1333,22 +1331,18 @@ void LLViewerParcelMgr::sendParcelPropertiesUpdate(LLParcel* parcel, bool use_ag void LLViewerParcelMgr::setHoverParcel(const LLVector3d& pos) { static U32 last_west, last_south; - + static LLUUID last_region; // only request parcel info if position has changed outside of the // last parcel grid step - U32 west_parcel_step = (U32) floor( pos.mdV[VX] / PARCEL_GRID_STEP_METERS ); - U32 south_parcel_step = (U32) floor( pos.mdV[VY] / PARCEL_GRID_STEP_METERS ); - + const U32 west_parcel_step = (U32) floor( pos.mdV[VX] / PARCEL_GRID_STEP_METERS ); + const U32 south_parcel_step = (U32) floor( pos.mdV[VY] / PARCEL_GRID_STEP_METERS ); + if ((west_parcel_step == last_west) && (south_parcel_step == last_south)) { + // We are staying in same segment return; } - else - { - last_west = west_parcel_step; - last_south = south_parcel_step; - } LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( pos ); if (!region) @@ -1356,34 +1350,95 @@ void LLViewerParcelMgr::setHoverParcel(const LLVector3d& pos) return; } + LLUUID region_id = region->getRegionID(); + LLVector3 pos_in_region = region->getPosRegionFromGlobal(pos); - // Send a rectangle around the point. - // This means the parcel sent back is at least a rectangle around the point, - // which is more efficient for public land. Fewer requests are sent. JC - LLVector3 wsb_region = region->getPosRegionFromGlobal( pos ); + bool request_properties = false; + if (region_id != last_region) + { + request_properties = true; + } + else + { + // Check if new position is in same parcel. + // This check is not ideal, since it checks by way of straight lines. + // So sometimes (small parcel in the middle of large one) it can + // decide that parcel actually changed, but it still allows to + // reduce amount of requests significantly - F32 west = PARCEL_GRID_STEP_METERS * floor( wsb_region.mV[VX] / PARCEL_GRID_STEP_METERS ); - F32 south = PARCEL_GRID_STEP_METERS * floor( wsb_region.mV[VY] / PARCEL_GRID_STEP_METERS ); + S32 west_parcel_local = (S32)(pos_in_region.mV[VX] / PARCEL_GRID_STEP_METERS); + S32 south_parcel_local = (S32)(pos_in_region.mV[VY] / PARCEL_GRID_STEP_METERS); - F32 east = west + PARCEL_GRID_STEP_METERS; - F32 north = south + PARCEL_GRID_STEP_METERS; + LLViewerParcelOverlay* overlay = region->getParcelOverlay(); + if (!overlay) + { + request_properties = true; + } + while (!request_properties && west_parcel_step < last_west) + { + S32 segment_shift = last_west - west_parcel_step; + request_properties = overlay->parcelLineFlags(south_parcel_local, west_parcel_local + segment_shift) & PARCEL_WEST_LINE; + last_west--; + } + while (!request_properties && south_parcel_step < last_south) + { + S32 segment_shift = last_south - south_parcel_step; + request_properties = overlay->parcelLineFlags(south_parcel_local + segment_shift, west_parcel_local) & PARCEL_SOUTH_LINE; + last_south--; + } + // Note: could have just swapped values, reused first two 'while' and set last_south, last_west separately, + // but this looks to be easier to understand/straightforward/less bulky + while (!request_properties && west_parcel_step > last_west) + { + S32 segment_shift = west_parcel_step - last_west; + request_properties = overlay->parcelLineFlags(south_parcel_local, west_parcel_local - segment_shift + 1) & PARCEL_WEST_LINE; + last_west++; + } + while (!request_properties && south_parcel_step > last_south) + { + S32 segment_shift = south_parcel_step - last_south; + request_properties = overlay->parcelLineFlags(south_parcel_local - segment_shift + 1, west_parcel_local) & PARCEL_SOUTH_LINE; + last_south++; + } - // Send request message - LLMessageSystem *msg = gMessageSystem; - msg->newMessageFast(_PREHASH_ParcelPropertiesRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); - msg->nextBlockFast(_PREHASH_ParcelData); - msg->addS32Fast(_PREHASH_SequenceID, HOVERED_PARCEL_SEQ_ID ); - msg->addF32Fast(_PREHASH_West, west ); - msg->addF32Fast(_PREHASH_South, south ); - msg->addF32Fast(_PREHASH_East, east ); - msg->addF32Fast(_PREHASH_North, north ); - msg->addBOOL("SnapSelection", FALSE ); - msg->sendReliable( region->getHost() ); + // if (!request_properties) last_south and last_west will be equal to new values + } - mHoverRequestResult = PARCEL_RESULT_NO_DATA; + if (request_properties) + { + last_west = west_parcel_step; + last_south = south_parcel_step; + last_region = region_id; + + LL_DEBUGS("ParcelMgr") << "Requesting parcel properties on hover, for " << pos << LL_ENDL; + + + // Send a rectangle around the point. + // This means the parcel sent back is at least a rectangle around the point, + // which is more efficient for public land. Fewer requests are sent. JC + F32 west = PARCEL_GRID_STEP_METERS * floor(pos_in_region.mV[VX] / PARCEL_GRID_STEP_METERS); + F32 south = PARCEL_GRID_STEP_METERS * floor(pos_in_region.mV[VY] / PARCEL_GRID_STEP_METERS); + + F32 east = west + PARCEL_GRID_STEP_METERS; + F32 north = south + PARCEL_GRID_STEP_METERS; + + // Send request message + LLMessageSystem *msg = gMessageSystem; + msg->newMessageFast(_PREHASH_ParcelPropertiesRequest); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_ParcelData); + msg->addS32Fast(_PREHASH_SequenceID, HOVERED_PARCEL_SEQ_ID); + msg->addF32Fast(_PREHASH_West, west); + msg->addF32Fast(_PREHASH_South, south); + msg->addF32Fast(_PREHASH_East, east); + msg->addF32Fast(_PREHASH_North, north); + msg->addBOOL("SnapSelection", FALSE); + msg->sendReliable(region->getHost()); + + mHoverRequestResult = PARCEL_RESULT_NO_DATA; + } } @@ -1472,7 +1527,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use if (request_result == PARCEL_RESULT_NO_DATA) { // no valid parcel data - LL_INFOS() << "no valid parcel data" << LL_ENDL; + LL_INFOS("ParcelMgr") << "no valid parcel data" << LL_ENDL; return; } @@ -1504,7 +1559,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use } else { - LL_INFOS() << "out of order agent parcel sequence id " << sequence_id + LL_INFOS("ParcelMgr") << "out of order agent parcel sequence id " << sequence_id << " last good " << parcel_mgr.mAgentParcelSequenceID << LL_ENDL; return; @@ -1552,6 +1607,8 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use msg->getS32("ParcelData", "OtherCleanTime", other_clean_time ); + LL_DEBUGS("ParcelMgr") << "Processing parcel " << local_id << " update, target(sequence): " << sequence_id << LL_ENDL; + // Actually extract the data. if (parcel) { @@ -1790,7 +1847,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use } else { - LL_INFOS() << "Stopping parcel music (invalid audio stream URL)" << LL_ENDL; + LL_INFOS("ParcelMgr") << "Stopping parcel music (invalid audio stream URL)" << LL_ENDL; // clears the URL // null value causes fade out LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null); @@ -1798,7 +1855,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use } else if (!gAudiop->getInternetStreamURL().empty()) { - LL_INFOS() << "Stopping parcel music (parcel stream URL is empty)" << LL_ENDL; + LL_INFOS("ParcelMgr") << "Stopping parcel music (parcel stream URL is empty)" << LL_ENDL; // null value causes fade out LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null); } @@ -1827,7 +1884,7 @@ void LLViewerParcelMgr::optionally_start_music(const std::string& music_url) gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) && gSavedSettings.getBOOL("MediaTentativeAutoPlay"))) { - LL_INFOS() << "Starting parcel music " << music_url << LL_ENDL; + LL_INFOS("ParcelMgr") << "Starting parcel music " << music_url << LL_ENDL; LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(music_url); } else @@ -1855,7 +1912,7 @@ void LLViewerParcelMgr::processParcelAccessListReply(LLMessageSystem *msg, void if (parcel_id != parcel->getLocalID()) { - LL_WARNS_ONCE("") << "processParcelAccessListReply for parcel " << parcel_id + LL_WARNS_ONCE("ParcelMgr") << "processParcelAccessListReply for parcel " << parcel_id << " which isn't the selected parcel " << parcel->getLocalID()<< LL_ENDL; return; } diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp index 4fd423b6f4..7c3dd00e1a 100644 --- a/indra/newview/llviewerparceloverlay.cpp +++ b/indra/newview/llviewerparceloverlay.cpp @@ -274,6 +274,23 @@ U8 LLViewerParcelOverlay::ownership( const LLVector3& pos) const return ownership(row, column); } +U8 LLViewerParcelOverlay::parcelLineFlags(const LLVector3& pos) const +{ + S32 row = S32(pos.mV[VY] / PARCEL_GRID_STEP_METERS); + S32 column = S32(pos.mV[VX] / PARCEL_GRID_STEP_METERS); + return parcelLineFlags(row, column); +} +U8 LLViewerParcelOverlay::parcelLineFlags(S32 row, S32 col) const +{ + U8 flags = PARCEL_WEST_LINE | PARCEL_SOUTH_LINE; + if (row > mParcelGridsPerEdge || col > mParcelGridsPerEdge) + { + LL_WARNS() << "Attempted to get ownership out of region's overlay, row: " << row << " col: " << col << LL_ENDL; + return flags; + } + return mOwnership[row * mParcelGridsPerEdge + col] & flags; +} + F32 LLViewerParcelOverlay::getOwnedRatio() const { S32 size = mParcelGridsPerEdge * mParcelGridsPerEdge; diff --git a/indra/newview/llviewerparceloverlay.h b/indra/newview/llviewerparceloverlay.h index 14a2af5354..e30dbf17b3 100644 --- a/indra/newview/llviewerparceloverlay.h +++ b/indra/newview/llviewerparceloverlay.h @@ -71,6 +71,8 @@ public: S32 renderPropertyLines(); U8 ownership( const LLVector3& pos) const; + U8 parcelLineFlags( const LLVector3& pos) const; + U8 parcelLineFlags(S32 row, S32 col) const; // MANIPULATE void uncompressLandOverlay(S32 chunk, U8 *compressed_overlay); diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index b3d561edd5..6d8b27ff2d 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -407,7 +407,8 @@ void LLViewerShaderMgr::setShaders() return; } - LLGLSLShader::sIndexedTextureChannels = llmax(llmin(gGLManager.mNumTextureImageUnits, (S32) gSavedSettings.getU32("RenderMaxTextureIndex")), 1); + static LLCachedControl max_texture_index(gSavedSettings, "RenderMaxTextureIndex", 16); + LLGLSLShader::sIndexedTextureChannels = llmax(llmin(gGLManager.mNumTextureImageUnits, (S32) max_texture_index), 1); //NEVER use more than 16 texture channels (work around for prevalent driver bug) LLGLSLShader::sIndexedTextureChannels = llmin(LLGLSLShader::sIndexedTextureChannels, 16); diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 092b51238e..68a9994bee 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -100,7 +100,7 @@ const S32 MAX_CACHED_RAW_TERRAIN_IMAGE_AREA = 128 * 128; const S32 DEFAULT_ICON_DIMENTIONS = 32; S32 LLViewerTexture::sMinLargeImageSize = 65536; //256 * 256. S32 LLViewerTexture::sMaxSmallImageSize = MAX_CACHED_RAW_IMAGE_AREA; -BOOL LLViewerTexture::sFreezeImageScalingDown = FALSE; +bool LLViewerTexture::sFreezeImageUpdates = false; F32 LLViewerTexture::sCurrentTime = 0.0f; F32 LLViewerTexture::sTexelPixelRatio = 1.0f; @@ -474,6 +474,7 @@ void LLViewerTexture::initClass() // tuning params const F32 discard_bias_delta = .25f; const F32 discard_delta_time = 0.5f; +const F32 GPU_MEMORY_CHECK_WAIT_TIME = 1.0f; // non-const (used externally F32 texmem_lower_bound_scale = 0.85f; F32 texmem_middle_bound_scale = 0.925f; @@ -483,53 +484,68 @@ static LLTrace::BlockTimerStatHandle FTM_TEXTURE_MEMORY_CHECK("Memory Check"); //static bool LLViewerTexture::isMemoryForTextureLow() { - const F32 WAIT_TIME = 1.0f; //second - static LLFrameTimer timer; + // Note: we need to figure out a better source for 'min' values, + // what is free for low end at minimal settings is 'nothing left' + // for higher end gpus at high settings. + const S32Megabytes MIN_FREE_TEXTURE_MEMORY(20); + const S32Megabytes MIN_FREE_MAIN_MEMORY(100); - if(timer.getElapsedTimeF32() < WAIT_TIME) //call this once per second. - { - return false; - } - timer.reset(); + S32Megabytes gpu; + S32Megabytes physical; + getGPUMemoryForTextures(gpu, physical); - LL_RECORD_BLOCK_TIME(FTM_TEXTURE_MEMORY_CHECK); + return (gpu < MIN_FREE_TEXTURE_MEMORY) || (physical < MIN_FREE_MAIN_MEMORY); +} - const S32Megabytes MIN_FREE_TEXTURE_MEMORY(20); //MB Changed to 20 MB per MAINT-6882 - const S32Megabytes MIN_FREE_MAIN_MEMORY(100); //MB +//static +bool LLViewerTexture::isMemoryForTextureSuficientlyFree() +{ + const S32Megabytes DESIRED_FREE_TEXTURE_MEMORY(50); + const S32Megabytes DESIRED_FREE_MAIN_MEMORY(200); - bool low_mem = false; - if (gGLManager.mHasATIMemInfo) - { - S32 meminfo[4]; - glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo); + S32Megabytes gpu; + S32Megabytes physical; + getGPUMemoryForTextures(gpu, physical); - if((S32Megabytes)meminfo[0] < MIN_FREE_TEXTURE_MEMORY) - { - low_mem = true; - } + return (gpu > DESIRED_FREE_TEXTURE_MEMORY) && (physical > DESIRED_FREE_MAIN_MEMORY); +} - if(!low_mem) //check main memory, only works for windows. - { - LLMemory::updateMemoryInfo(); - if(LLMemory::getAvailableMemKB() < MIN_FREE_TEXTURE_MEMORY) - { - low_mem = true; - } - } - } - //Enabled this branch per MAINT-6882 - else if (gGLManager.mHasNVXMemInfo) - { - S32 free_memory; - glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &free_memory); - - if ((S32Megabytes)(free_memory / 1024) < MIN_FREE_TEXTURE_MEMORY) - { - low_mem = true; - } - } +//static +void LLViewerTexture::getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &physical) +{ + static LLFrameTimer timer; + static S32Megabytes gpu_res = S32Megabytes(S32_MAX); + static S32Megabytes physical_res = S32Megabytes(S32_MAX); - return low_mem; + if (timer.getElapsedTimeF32() < GPU_MEMORY_CHECK_WAIT_TIME) //call this once per second. + { + gpu = gpu_res; + physical = physical_res; + return; + } + timer.reset(); + + LL_RECORD_BLOCK_TIME(FTM_TEXTURE_MEMORY_CHECK); + + if (gGLManager.mHasATIMemInfo) + { + S32 meminfo[4]; + glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo); + gpu_res = (S32Megabytes)meminfo[0]; + + //check main memory, only works for windows. + LLMemory::updateMemoryInfo(); + physical_res = LLMemory::getAvailableMemKB(); + } + else if (gGLManager.mHasNVXMemInfo) + { + S32 free_memory; + glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &free_memory); + gpu_res = (S32Megabytes)(free_memory / 1024); + } + + gpu = gpu_res; + physical = physical_res; } static LLTrace::BlockTimerStatHandle FTM_TEXTURE_UPDATE_MEDIA("Media"); @@ -572,15 +588,20 @@ void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity sEvaluationTimer.reset(); } } - else if(sEvaluationTimer.getElapsedTimeF32() > discard_delta_time && isMemoryForTextureLow()) + else if(isMemoryForTextureLow()) { - sDesiredDiscardBias += discard_bias_delta; - sEvaluationTimer.reset(); + // Note: isMemoryForTextureLow() uses 1s delay, make sure we waited enough for it to recheck + if (sEvaluationTimer.getElapsedTimeF32() > GPU_MEMORY_CHECK_WAIT_TIME) + { + sDesiredDiscardBias += discard_bias_delta; + sEvaluationTimer.reset(); + } } - else if (sDesiredDiscardBias > 0.0f && - sBoundTextureMemory < sMaxBoundTextureMemory * texmem_lower_bound_scale && - sTotalTextureMemory < sMaxTotalTextureMem * texmem_lower_bound_scale) - { + else if (sDesiredDiscardBias > 0.0f + && sBoundTextureMemory < sMaxBoundTextureMemory * texmem_lower_bound_scale + && sTotalTextureMemory < sMaxTotalTextureMem * texmem_lower_bound_scale + && isMemoryForTextureSuficientlyFree()) + { // If we are using less texture memory than we should, // scale down the desired discard level if (sEvaluationTimer.getElapsedTimeF32() > discard_delta_time) @@ -590,14 +611,8 @@ void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity } } sDesiredDiscardBias = llclamp(sDesiredDiscardBias, desired_discard_bias_min, desired_discard_bias_max); - - F32 camera_moving_speed = LLViewerCamera::getInstance()->getAverageSpeed(); - F32 camera_angular_speed = LLViewerCamera::getInstance()->getAverageAngularSpeed(); - sCameraMovingBias = llmax(0.2f * camera_moving_speed, 2.0f * camera_angular_speed - 1); - sCameraMovingDiscardBias = (S8)(sCameraMovingBias); - LLViewerTexture::sFreezeImageScalingDown = (sBoundTextureMemory < 0.75f * sMaxBoundTextureMemory * texmem_middle_bound_scale) && - (sTotalTextureMemory < 0.75f * sMaxTotalTextureMem * texmem_middle_bound_scale); + LLViewerTexture::sFreezeImageUpdates = sDesiredDiscardBias > (desired_discard_bias_max - 1.0f); } //end of static functions @@ -3125,9 +3140,9 @@ S8 LLViewerLODTexture::getType() const return LLViewerTexture::LOD_TEXTURE; } -BOOL LLViewerLODTexture::isUpdateFrozen() +bool LLViewerLODTexture::isUpdateFrozen() { - return LLViewerTexture::sFreezeImageScalingDown && !getDiscardLevel(); + return LLViewerTexture::sFreezeImageUpdates; } // This is gauranteed to get called periodically for every texture @@ -3253,9 +3268,16 @@ void LLViewerLODTexture::processTextureStats() (!getBoundRecently() || mDesiredDiscardLevel >= mCachedRawDiscardLevel)) { scaleDown(); - } } + + if (isUpdateFrozen() // we are out of memory and nearing max allowed bias + && mBoostLevel < LLGLTexture::BOOST_SCULPTED + && mDesiredDiscardLevel < current_discard) + { + // stop requesting more + mDesiredDiscardLevel = current_discard; + } } if(mForceToSaveRawImage && mDesiredSavedRawDiscardLevel >= 0) diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index 5d89f9f029..7cbcc931b1 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -186,6 +186,9 @@ private: virtual void switchToCachedImage(); static bool isMemoryForTextureLow() ; + static bool isMemoryForTextureSuficientlyFree(); + static void getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &physical); + protected: LLUUID mID; S32 mTextureListType; // along with mID identifies where to search for this texture in TextureList @@ -227,7 +230,7 @@ public: static S32 sMaxSculptRez ; static S32 sMinLargeImageSize ; static S32 sMaxSmallImageSize ; - static BOOL sFreezeImageScalingDown ;//do not scale down image res if set. + static bool sFreezeImageUpdates; static F32 sCurrentTime ; enum EDebugTexels @@ -543,7 +546,7 @@ public: /*virtual*/ S8 getType() const; // Process image stats to determine priority/quality requirements. /*virtual*/ void processTextureStats(); - BOOL isUpdateFrozen() ; + bool isUpdateFrozen() ; private: void init(bool firstinit) ; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 321f774210..20fa327790 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -5992,7 +5992,7 @@ void LLVOAvatar::rebuildAttachmentOverrides() LLViewerObject *vo = *at_it; // Attached animated objects affect joints in their control // avs, not the avs to which they are attached. - if (!vo->isAnimatedObject()) + if (vo && !vo->isAnimatedObject()) { addAttachmentOverridesForObject(vo); } @@ -6043,7 +6043,7 @@ void LLVOAvatar::updateAttachmentOverrides() LLViewerObject *vo = *at_it; // Attached animated objects affect joints in their control // avs, not the avs to which they are attached. - if (!vo->isAnimatedObject()) + if (vo && !vo->isAnimatedObject()) { addAttachmentOverridesForObject(vo, &meshes_seen); } @@ -7036,13 +7036,34 @@ U32 LLVOAvatar::getNumAttachments() const return num_attachments; } +//----------------------------------------------------------------------------- +// getMaxAttachments() +//----------------------------------------------------------------------------- +S32 LLVOAvatar::getMaxAttachments() const +{ + const S32 MAX_AGENT_ATTACHMENTS = 38; + + S32 max_attach = MAX_AGENT_ATTACHMENTS; + + if (gAgent.getRegion()) + { + LLSD features; + gAgent.getRegion()->getSimulatorFeatures(features); + if (features.has("MaxAgentAttachments")) + { + max_attach = features["MaxAgentAttachments"].asInteger(); + } + } + return max_attach; +} + //----------------------------------------------------------------------------- // canAttachMoreObjects() // Returns true if we can attach more objects. //----------------------------------------------------------------------------- BOOL LLVOAvatar::canAttachMoreObjects(U32 n) const { - return (getNumAttachments() + n) <= MAX_AGENT_ATTACHMENTS; + return (getNumAttachments() + n) <= getMaxAttachments(); } //----------------------------------------------------------------------------- @@ -7070,7 +7091,7 @@ S32 LLVOAvatar::getMaxAnimatedObjectAttachments() const S32 max_attach = 0; if (gSavedSettings.getBOOL("AnimatedObjectsIgnoreLimits")) { - max_attach = MAX_AGENT_ATTACHMENTS; + max_attach = getMaxAttachments(); } else { diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index deb22617a4..b603381e6d 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -75,6 +75,8 @@ class LLTexGlobalColor; struct LLAppearanceMessageContents; class LLViewerJointMesh; +const F32 MAX_AVATAR_LOD_FACTOR = 1.0f; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // LLVOAvatar @@ -809,6 +811,7 @@ public: BOOL hasHUDAttachment() const; LLBBox getHUDBBox() const; void resetHUDAttachments(); + S32 getMaxAttachments() const; BOOL canAttachMoreObjects(U32 n=1) const; S32 getMaxAnimatedObjectAttachments() const; BOOL canAttachMoreAnimatedObjects(U32 n=1) const; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 976ced7d3e..3793d6b9b2 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -1380,7 +1380,8 @@ BOOL LLVOVolume::calcLOD() mLODDistance = distance; mLODRadius = radius; - if (gSavedSettings.getBOOL("DebugObjectLODs")) + static LLCachedControl debug_lods(gSavedSettings, "DebugObjectLODs", false); + if (debug_lods) { if (getAvatar() && isRootEdit()) { @@ -4276,10 +4277,16 @@ F32 LLVOVolume::getBinRadius() F32 scale = 1.f; - S32 size_factor = llmax(gSavedSettings.getS32("OctreeStaticObjectSizeFactor"), 1); - S32 attachment_size_factor = llmax(gSavedSettings.getS32("OctreeAttachmentSizeFactor"), 1); - LLVector3 distance_factor = gSavedSettings.getVector3("OctreeDistanceFactor"); - LLVector3 alpha_distance_factor = gSavedSettings.getVector3("OctreeAlphaDistanceFactor"); + static LLCachedControl octree_size_factor(gSavedSettings, "OctreeStaticObjectSizeFactor", 3); + static LLCachedControl octree_attachment_size_factor(gSavedSettings, "OctreeAttachmentSizeFactor", 4); + static LLCachedControl octree_distance_factor(gSavedSettings, "OctreeDistanceFactor", LLVector3(0.01f, 0.f, 0.f)); + static LLCachedControl octree_alpha_distance_factor(gSavedSettings, "OctreeAlphaDistanceFactor", LLVector3(0.1f, 0.f, 0.f)); + + S32 size_factor = llmax((S32)octree_size_factor, 1); + S32 attachment_size_factor = llmax((S32)octree_attachment_size_factor, 1); + LLVector3 distance_factor = octree_distance_factor; + LLVector3 alpha_distance_factor = octree_alpha_distance_factor; + const LLVector4a* ext = mDrawable->getSpatialExtents(); BOOL shrink_wrap = mDrawable->isAnimating(); @@ -5355,8 +5362,10 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) U32 useage = group->getSpatialPartition()->mBufferUsage; - U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask); - U32 max_total = (gSavedSettings.getS32("RenderMaxNodeSize")*1024)/LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask); + LLCachedControl max_vbo_size(gSavedSettings, "RenderMaxVBOSize", 512); + LLCachedControl max_node_size(gSavedSettings, "RenderMaxNodeSize", 65536); + U32 max_vertices = (max_vbo_size * 1024)/LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask); + U32 max_total = (max_node_size * 1024) / LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask); max_vertices = llmin(max_vertices, (U32) 65535); U32 cur_total = 0; @@ -6109,7 +6118,8 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace #endif //calculate maximum number of vertices to store in a single buffer - U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask); + LLCachedControl max_vbo_size(gSavedSettings, "RenderMaxVBOSize", 512); + U32 max_vertices = (max_vbo_size * 1024)/LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask); max_vertices = llmin(max_vertices, (U32) 65535); { @@ -6152,7 +6162,8 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace texture_index_channels = gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels; } - texture_index_channels = llmin(texture_index_channels, (S32) gSavedSettings.getU32("RenderMaxTextureIndex")); + static LLCachedControl max_texture_index(gSavedSettings, "RenderMaxTextureIndex", 16); + texture_index_channels = llmin(texture_index_channels, (S32) max_texture_index); //NEVER use more than 16 texture index channels (workaround for prevalent driver bug) texture_index_channels = llmin(texture_index_channels, 16); diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 0882fc095d..13db9c39b7 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -54,6 +54,8 @@ enum LLVolumeInterfaceType INTERFACE_FLEXIBLE = 1, }; +const F32 MAX_LOD_FACTOR = 4.0f; + class LLRiggedVolume : public LLVolume { diff --git a/indra/newview/llvowlsky.cpp b/indra/newview/llvowlsky.cpp index 3b9b96e9f1..2cb5fc81b0 100644 --- a/indra/newview/llvowlsky.cpp +++ b/indra/newview/llvowlsky.cpp @@ -335,7 +335,8 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable) } { - const U32 max_buffer_bytes = gSavedSettings.getS32("RenderMaxVBOSize")*1024; + LLCachedControl max_vbo_size(gSavedSettings, "RenderMaxVBOSize", 512); + const U32 max_buffer_bytes = max_vbo_size * 1024; const U32 data_mask = LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK; const U32 max_verts = max_buffer_bytes / LLVertexBuffer::calcVertexSize(data_mask); diff --git a/indra/newview/llwatchdog.cpp b/indra/newview/llwatchdog.cpp index 2782cd9545..dd6c77ca7d 100644 --- a/indra/newview/llwatchdog.cpp +++ b/indra/newview/llwatchdog.cpp @@ -155,7 +155,7 @@ void LLWatchdogTimeout::ping(const std::string& state) // LLWatchdog LLWatchdog::LLWatchdog() : - mSuspectsAccessMutex(NULL), + mSuspectsAccessMutex(), mTimer(NULL), mLastClockCount(0), mKillerCallback(&default_killer_callback) @@ -185,7 +185,7 @@ void LLWatchdog::init(killer_event_callback func) mKillerCallback = func; if(!mSuspectsAccessMutex && !mTimer) { - mSuspectsAccessMutex = new LLMutex(NULL); + mSuspectsAccessMutex = new LLMutex(); mTimer = new LLWatchdogTimerThread(); mTimer->setSleepTime(WATCHDOG_SLEEP_TIME_USEC / 1000); mLastClockCount = LLTimer::getTotalTime(); diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp index 93d1dacf1f..b27257a262 100644 --- a/indra/newview/llworldmapview.cpp +++ b/indra/newview/llworldmapview.cpp @@ -465,7 +465,11 @@ void LLWorldMapView::draw() mesg, 0, llfloor(left + 3), llfloor(bottom + 2), LLColor4::white, - LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW); + LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW, + S32_MAX, //max_chars + sMapScale, //max_pixels + NULL, + TRUE); //use ellipses } } } @@ -1756,9 +1760,12 @@ BOOL LLWorldMapView::handleDoubleClick( S32 x, S32 y, MASK mask ) case MAP_ITEM_LAND_FOR_SALE_ADULT: { LLVector3d pos_global = viewPosToGlobal(x, y); - LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromPosGlobal(pos_global); - LLFloaterReg::hideInstance("world_map"); - LLFloaterReg::showInstance("search", LLSD().with("category", "land").with("query", info->getName())); + std::string sim_name; + if (LLWorldMap::getInstance()->simNameFromPosGlobal(pos_global, sim_name)) + { + LLFloaterReg::hideInstance("world_map"); + LLFloaterReg::showInstance("search", LLSD().with("category", "land").with("query", sim_name)); + } break; } case MAP_ITEM_CLASSIFIED: diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index 143c97fca4..8e2539606b 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -362,6 +362,10 @@ void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip, const { httpOpts->setRetries(httpParams["retries"].asInteger()); } + if (httpParams.has("DNSCacheTimeout")) + { + httpOpts->setDNSCacheTimeout(httpParams["DNSCacheTimeout"].asInteger()); + } bool vefifySSLCert = !gSavedSettings.getBOOL("NoVerifySSLCert"); mCertStore = gSavedSettings.getString("CertStore"); @@ -483,38 +487,24 @@ void LLXMLRPCTransaction::Impl::setHttpStatus(const LLCore::HttpStatus &status) { CURLcode code = static_cast(status.toULong()); std::string message; - std::string uri = "http://secondlife.com/community/support.php"; + std::string uri = "http://support.secondlife.com"; LLURI failuri(mURI); - + LLStringUtil::format_map_t args; switch (code) { case CURLE_COULDNT_RESOLVE_HOST: - message = - std::string("DNS could not resolve the host name(") + failuri.hostName() + ").\n" - "Please verify that you can connect to the www.secondlife.com\n" - "web site. If you can, but continue to receive this error,\n" - "please go to the support section and report this problem."; + args["[HOSTNAME]"] = failuri.hostName(); + message = LLTrans::getString("couldnt_resolve_host", args); break; case CURLE_SSL_PEER_CERTIFICATE: - message = - "The login server couldn't verify itself via SSL.\n" - "If you continue to receive this error, please go\n" - "to the Support section of the SecondLife.com web site\n" - "and report the problem."; + message = LLTrans::getString("ssl_peer_certificate"); break; case CURLE_SSL_CACERT: - case CURLE_SSL_CONNECT_ERROR: - message = - "Often this means that your computer\'s clock is set incorrectly.\n" - "Please go to Control Panels and make sure the time and date\n" - "are set correctly.\n" - "Also check that your network and firewall are set up correctly.\n" - "If you continue to receive this error, please go\n" - "to the Support section of the SecondLife.com web site\n" - "and report the problem."; + case CURLE_SSL_CONNECT_ERROR: + message = LLTrans::getString("ssl_connect_error"); break; default: diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index e8c9909f8c..a72244929e 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -4139,7 +4139,12 @@ void LLPipeline::renderHighlights() glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFFF); glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); - + + if (canUseVertexShaders()) + { + gHighlightProgram.bind(); + } + gGL.setColorMask(false, false); for (std::set::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); ++iter) { @@ -10507,6 +10512,11 @@ void LLPipeline::generateHighlight(LLCamera& camera) gGL.setColorMask(true, true); mHighlight.clear(); + if (canUseVertexShaders()) + { + gHighlightProgram.bind(); + } + gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep); for (std::set::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); ) { diff --git a/indra/newview/skins/default/default_languages.xml b/indra/newview/skins/default/default_languages.xml new file mode 100644 index 0000000000..357930e1c5 --- /dev/null +++ b/indra/newview/skins/default/default_languages.xml @@ -0,0 +1,39 @@ + + + diff --git a/indra/newview/skins/default/xui/da/panel_preferences_general.xml b/indra/newview/skins/default/xui/da/panel_preferences_general.xml index 5702d48e97..624c6634cc 100644 --- a/indra/newview/skins/default/xui/da/panel_preferences_general.xml +++ b/indra/newview/skins/default/xui/da/panel_preferences_general.xml @@ -4,7 +4,6 @@ Sprog: - diff --git a/indra/newview/skins/default/xui/de/floater_bulk_perms.xml b/indra/newview/skins/default/xui/de/floater_bulk_perms.xml index 27a74c874e..9454933264 100644 --- a/indra/newview/skins/default/xui/de/floater_bulk_perms.xml +++ b/indra/newview/skins/default/xui/de/floater_bulk_perms.xml @@ -38,17 +38,17 @@ Gruppe: - + Jeder: - + Nächster Eigentümer: - - - + + + + + + + + + + + + + width="170" + tool_tip="The name is limited to 63 characters. Longer prim names are cut short. Names can only consist of printable characters found in the ASCII-7 (non-extended) character set, with the exception of the vertical bar/pipe '|'." /> + width="170" + tool_tip="When people have 'Hover Tips on All Objects' selected in the viewer's settings, they'll see the object description pop-up for any object under their mouse pointer. The prim description is limited to 127 bytes any string longer then that will be truncated." /> + left_pad="10" + tool_tip="A click action enables you to interact with an object with a single left click. Each click action has a special cursor indicating what it does. Some click actions have requirements to function. For example Touch and Pay require scripts" > + width="97" + tool_tip="Lets people buy this object, its content or it copy inworld for specified price." /> + width="89" + tool_tip="Select whether purchaser will receive a copy, copy of the content or item itself." > diff --git a/indra/newview/skins/default/xui/en/floater_top_objects.xml b/indra/newview/skins/default/xui/en/floater_top_objects.xml index 36ceddd305..b82fe43e74 100644 --- a/indra/newview/skins/default/xui/en/floater_top_objects.xml +++ b/indra/newview/skins/default/xui/en/floater_top_objects.xml @@ -2,7 +2,7 @@ - [COUNT] scripts taking a total of [TIME] ms + [COUNT] scripts taking a total of [TIME] ms and using [MEMORY] KB @@ -273,28 +273,4 @@ - - diff --git a/indra/newview/skins/default/xui/en/fonts.xml b/indra/newview/skins/default/xui/en/fonts.xml index 82027d9e7c..8b1d50e58f 100644 --- a/indra/newview/skins/default/xui/en/fonts.xml +++ b/indra/newview/skins/default/xui/en/fonts.xml @@ -9,6 +9,7 @@ gulim.ttc simhei.ttf ArialUni.ttf + msyh.ttc ヒラギノ角ゴシック W3.ttc @@ -19,6 +20,7 @@ AppleGothic.ttf AppleSDGothicNeo-Regular.otf 华文细黑.ttf + PingFang.ttc diff --git a/indra/newview/skins/default/xui/en/language_settings.xml b/indra/newview/skins/default/xui/en/language_settings.xml index 51779e4bfd..d418fc38e3 100644 --- a/indra/newview/skins/default/xui/en/language_settings.xml +++ b/indra/newview/skins/default/xui/en/language_settings.xml @@ -42,6 +42,7 @@ wkday,datetime,slt ampm,datetime,slt hour12,datetime,slt + timezone,datetime,slt mthnum,datetime,local wkday,datetime,local diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 42744b561f..cac84cfccf 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -73,6 +73,13 @@ function="Floater.ToggleOrBringToFront" parameter="experiences"/> + + + You do not have permission to copy the following items: -[ITEMS] +<nolink>[ITEMS]</nolink> and will lose it from your inventory if you give it away. Do you really want to offer these items? confirm - -The runtime script permission requested by '<nolink>[OBJECTNAME]</nolink>', an object owned by '[NAME]', isn't recognized by the viewer and can't be granted. - -To grant this permission please update your viewer to the latest version from [DOWNLOADURL]. - confirm -
-