Automated merge with file:///Users/nat/linden/viewer-gridselect

master
Nat Goodspeed 2019-04-26 11:17:53 -04:00
commit 0d596aa4de
379 changed files with 5107 additions and 6139 deletions

View File

@ -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

View File

@ -3,8 +3,8 @@
# cmake_minimum_required should appear before any
# other commands to guarantee full compatibility
# with the version specified
## prior to 3.4, the Windows manifest handling was missing
cmake_minimum_required(VERSION 3.4.0 FATAL_ERROR)
## 3.8 added VS_DEBUGGER_WORKING_DIRECTORY support
cmake_minimum_required(VERSION 3.8.0 FATAL_ERROR)
set(ROOT_PROJECT_NAME "SecondLife" CACHE STRING
"The root project/makefile/solution name. Defaults to SecondLife.")
@ -83,6 +83,12 @@ add_dependencies(viewer secondlife-bin)
add_subdirectory(${VIEWER_PREFIX}doxygen EXCLUDE_FROM_ALL)
# sets the 'startup project' for debugging from visual studio.
set_property(
DIRECTORY ${VIEWER_PREFIX}
PROPERTY VS_STARTUP_PROJECT secondlife-bin
)
if (LL_TESTS)
# Define after the custom targets are created so
# individual apps can add themselves as dependencies

View File

@ -151,6 +151,8 @@ endif (LINUX)
if (DARWIN)
# Warnings should be fatal -- thanks, Nicky Perian, for spotting reversed default
set(CLANG_DISABLE_FATAL_WARNINGS OFF)
set(CMAKE_CXX_LINK_FLAGS "-Wl,-headerpad_max_install_names,-search_paths_first")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_CXX_LINK_FLAGS}")
set(DARWIN_extra_cstar_flags "-Wno-unused-local-typedef -Wno-deprecated-declarations")

View File

@ -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

View File

@ -30,9 +30,8 @@
#include <map>
#include "llrun.h"
#include "llsd.h"
#include <atomic>
// Forward declarations
template <typename Type> class LLAtomic32;
typedef LLAtomic32<U32> LLAtomicU32;
class LLErrorThread;
class LLLiveFile;
#if LL_LINUX

View File

@ -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;
}
}
}
//---------------------------------------------------------------------

View File

@ -36,15 +36,22 @@
#include <boost/noncopyable.hpp>
#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 <mutex>
#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<std::mutex> 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
* <b>not</b> 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 <typename Type> class LLAtomic32
{
public:
LLAtomic32<Type>() {};
LLAtomic32<Type>(Type x) {apr_atomic_set32(&mData, apr_uint32_t(x)); };
~LLAtomic32<Type>() {};
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<U32> LLAtomicU32;
typedef LLAtomic32<S32> LLAtomicS32;
// File IO convenience functions.
// Returns NULL if the file fails to open, sets *sizep to file size if not NULL
// abbreviated flags

View File

@ -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"
//============================================================================

69
indra/llcommon/llatomic.h Normal file
View File

@ -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 <atomic>
template <typename Type, typename AtomicType = std::atomic< Type > > 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<U32, std::atomic_uint32_t> LLAtomicU32;
typedef LLAtomicBase<S32, std::atomic_int32_t> LLAtomicS32;
#else
typedef LLAtomicBase<U32, std::atomic_uint> LLAtomicU32;
typedef LLAtomicBase<S32, std::atomic_int> LLAtomicS32;
#endif
typedef LLAtomicBase<bool, std::atomic_bool> LLAtomicBool;
#endif // LL_LLATOMIC_H

View File

@ -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;
}

View File

@ -31,7 +31,7 @@
LLFixedBuffer::LLFixedBuffer(const U32 max_lines)
: LLLineBuffer(),
mMaxLines(max_lines),
mMutex(NULL)
mMutex()
{
mTimer.reset();
}

View File

@ -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;
}

View File

@ -28,6 +28,7 @@
#ifndef LL_LLINSTANCETRACKER_H
#define LL_LLINSTANCETRACKER_H
#include <atomic>
#include <map>
#include <typeinfo>
@ -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();

View File

@ -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;
}
}
//============================================================================

View File

@ -28,6 +28,19 @@
#define LL_LLMUTEX_H
#include "stdtypes.h"
#include <boost/noncopyable.hpp>
#if LL_WINDOWS
#pragma warning (push)
#pragma warning (disable:4265)
#endif
// 'std::_Pad' : class has virtual functions, but destructor is not virtual
#include <mutex>
#include <condition_variable>
#if LL_WINDOWS
#pragma warning (pop)
#endif
//============================================================================
@ -37,10 +50,6 @@
#include <map>
#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<U32, BOOL> 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 <b>not</b> 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

View File

@ -32,7 +32,7 @@
#include <map>
#include <set>
#include "llapr.h"
#include "llatomic.h"
#include "llthread.h"
#include "llsimplehash.h"
@ -128,7 +128,7 @@ public:
};
protected:
LLAtomic32<status_t> mStatus;
LLAtomicBase<status_t> 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<BOOL> 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<QueuedRequest*, queued_request_less> request_queue_t;
request_queue_t mRequestQueue;

View File

@ -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

View File

@ -29,12 +29,7 @@
#include <boost/noncopyable.hpp>
#include <boost/intrusive_ptr.hpp>
#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;
};
/**

View File

@ -1735,7 +1735,8 @@ bool LLStringUtilBase<T>::startsWith(
const string_type& substr)
{
if(string.empty() || (substr.empty())) return false;
if(0 == string.find(substr)) return true;
if (substr.length() > string.length()) return false;
if (0 == string.compare(0, substr.length(), substr)) return true;
return false;
}
@ -1746,9 +1747,11 @@ bool LLStringUtilBase<T>::endsWith(
const string_type& substr)
{
if(string.empty() || (substr.empty())) return false;
std::string::size_type idx = string.rfind(substr);
if(std::string::npos == idx) return false;
return (idx == (string.size() - substr.size()));
size_t sub_len = substr.length();
size_t str_len = string.length();
if (sub_len > str_len) return false;
if (0 == string.compare(str_len - sub_len, sub_len, substr)) return true;
return false;
}
// static

View File

@ -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<LPBYTE>(&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);

View File

@ -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();
}
}

View File

@ -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 <thread>
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;

View File

@ -24,87 +24,6 @@
*/
#include "linden_common.h"
#include <apr_pools.h>
#include <apr_queue.h>
#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);
}

View File

@ -28,12 +28,20 @@
#define LL_LLTHREADSAFEQUEUE_H
#include "llexception.h"
#include <deque>
#include <string>
#if LL_WINDOWS
#pragma warning (push)
#pragma warning (disable:4265)
#endif
// 'std::_Pad' : class has virtual functions, but destructor is not virtual
#include <mutex>
#include <condition_variable>
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<typename ElementT>
LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(apr_pool_t * pool, unsigned int capacity):
mImplementation(pool, capacity)
LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(U32 capacity) :
mCapacity(capacity)
{
; // No op.
}
template<typename ElementT>
void LLThreadSafeQueue<ElementT>::pushFront(ElementT const & element)
{
ElementT * elementCopy = new ElementT(element);
try {
mImplementation.pushFront(elementCopy);
} catch (LLThreadSafeQueueInterrupt) {
delete elementCopy;
throw;
}
while (true)
{
std::unique_lock<std::mutex> lock1(mLock);
if (mStorage.size() < mCapacity)
{
mStorage.push_front(element);
mEmptyCond.notify_one();
return;
}
// Storage Full. Wait for signal.
mCapacityCond.wait(lock1);
}
}
template<typename ElementT>
bool LLThreadSafeQueue<ElementT>::tryPushFront(ElementT const & element)
{
ElementT * elementCopy = new ElementT(element);
bool result = mImplementation.tryPushFront(elementCopy);
if(!result) delete elementCopy;
return result;
std::unique_lock<std::mutex> 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<typename ElementT>
ElementT LLThreadSafeQueue<ElementT>::popBack(void)
{
ElementT * element = reinterpret_cast<ElementT *> (mImplementation.popBack());
ElementT result(*element);
delete element;
return result;
while (true)
{
std::unique_lock<std::mutex> 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<typename ElementT>
bool LLThreadSafeQueue<ElementT>::tryPopBack(ElementT & element)
{
void * storedElement;
bool result = mImplementation.tryPopBack(storedElement);
if(result) {
ElementT * elementPtr = reinterpret_cast<ElementT *>(storedElement);
element = *elementPtr;
delete elementPtr;
} else {
; // No op.
}
return result;
std::unique_lock<std::mutex> 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<typename ElementT>
size_t LLThreadSafeQueue<ElementT>::size(void)
{
return mImplementation.size();
std::lock_guard<std::mutex> lock(mLock);
return mStorage.size();
}
#endif

View File

@ -173,6 +173,19 @@ namespace
"-._~";
return s;
}
const std::string path()
{
static const std::string s =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
"$-_.+"
"!*'(),"
"{}|\\^~[]`"
"<>#%"
";/?:@&=";
return s;
}
const std::string sub_delims()
{
static const std::string s = "!$&'()*+,;=";
@ -187,6 +200,12 @@ namespace
{ return LLURI::escape(s, unreserved() + ":@!$'()*+,"); } // sub_delims - "&;=" + ":@"
std::string escapeQueryValue(const std::string& s)
{ return LLURI::escape(s, unreserved() + ":@!$'()*+,="); } // sub_delims - "&;" + ":@"
std::string escapeUriQuery(const std::string& s)
{ return LLURI::escape(s, unreserved() + ":@?&$;*+=%/"); }
std::string escapeUriData(const std::string& s)
{ return LLURI::escape(s, unreserved() + "%"); }
std::string escapeUriPath(const std::string& s)
{ return LLURI::escape(s, path()); }
}
//static
@ -202,6 +221,85 @@ std::string LLURI::escape(const std::string& str)
return escape(str, default_allowed, true);
}
//static
std::string LLURI::escapePathAndData(const std::string &str)
{
std::string result;
const std::string data_marker = "data:";
if (str.compare(0, data_marker.length(), data_marker) == 0)
{
// This is not url, but data, data part needs to be properly escaped
// data part is separated by ',' from header. Minimal data uri is "data:,"
// See "data URI scheme"
size_t separator = str.find(',');
if (separator != std::string::npos)
{
size_t header_size = separator + 1;
std::string header = str.substr(0, header_size);
// base64 is url-safe
if (header.find("base64") != std::string::npos)
{
// assume url-safe data
result = str;
}
else
{
std::string data = str.substr(header_size, str.length() - header_size);
// Notes: File can be partially pre-escaped, that's why escaping ignores '%'
// It somewhat limits user from displaying strings like "%20" in text
// but that's how viewer worked for a while and user can double-escape it
// Header doesn't need escaping
result = header + escapeUriData(data);
}
}
}
else
{
// try processing it as path with query separator
// The query component is indicated by the first question
// mark("?") character and terminated by a number sign("#")
size_t delim_pos = str.find('?');
if (delim_pos == std::string::npos)
{
// alternate separator
delim_pos = str.find(';');
}
if (delim_pos != std::string::npos)
{
size_t path_size = delim_pos + 1;
std::string query;
std::string fragment;
size_t fragment_pos = str.find('#');
if (fragment_pos != std::string::npos)
{
query = str.substr(path_size, fragment_pos - path_size);
fragment = str.substr(fragment_pos);
}
else
{
query = str.substr(path_size);
}
std::string path = str.substr(0, path_size);
result = escapeUriPath(path) + escapeUriQuery(query) + escapeUriPath(fragment);
}
}
if (result.empty())
{
// Not a known scheme or no data part, try just escaping as Uri path
result = escapeUriPath(str);
}
return result;
}
LLURI::LLURI()
{
}

View File

@ -157,6 +157,14 @@ public:
const std::string& allowed,
bool is_allowed_sorted = false);
/**
* @brief Break string into data part and path or sheme
* and escape path (if present) and data.
* Data part is not allowed to have path related symbols
* @param str The raw URI to escape.
*/
static std::string escapePathAndData(const std::string &str);
/**
* @brief unescape an escaped URI string.
*

View File

@ -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};

View File

@ -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)

View File

@ -33,7 +33,7 @@
#include <string>
#include "llqueuedthread.h"
#include "llapr.h"
#include "llatomic.h"
#define USE_FRAME_CALLBACK_MANAGER 0

View File

@ -355,7 +355,8 @@ bool HttpLibcurl::completeRequest(CURLM * multi_handle, CURL * handle, CURLcode
}
if (op->mStatus)
{
int http_status(HTTP_OK);
// note: CURLINFO_RESPONSE_CODE requires a long - https://curl.haxx.se/libcurl/c/CURLINFO_RESPONSE_CODE.html
long http_status(HTTP_OK);
if (handle)
{

View File

@ -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)

View File

@ -31,7 +31,7 @@
#include <vector>
#include "linden_common.h"
#include "llapr.h"
#include "llatomic.h"
#include "httpcommon.h"
#include "httprequest.h"
#include "_httppolicyglobal.h"

View File

@ -34,7 +34,7 @@
#include <boost/thread.hpp>
#include <boost/intrusive_ptr.hpp>
#include "llapr.h"
#include "llatomic.h"
namespace LLCoreInt

View File

@ -33,6 +33,7 @@
#include <boost/function.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include "apr.h" // thread-related functions
#include "_refcounted.h"
namespace LLCoreInt

View File

@ -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);

View File

@ -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

View File

@ -27,6 +27,7 @@
#include "linden_common.h"
#include "llapr.h" // thread-related functions
#include "llcrashlock.h"
#include "lldir.h"
#include "llsd.h"

View File

@ -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

View File

@ -35,7 +35,7 @@
LLImageDecodeThread::LLImageDecodeThread(bool threaded)
: LLQueuedThread("imagedecode", threaded)
{
mCreationMutex = new LLMutex(getAPRPool());
mCreationMutex = new LLMutex();
}
//virtual

View File

@ -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();
}
}

View File

@ -265,7 +265,7 @@ void LLBufferArray::setThreaded(bool threaded)
{
if(!mMutexp)
{
mMutexp = new LLMutex(NULL);
mMutexp = new LLMutex();
}
}
else

View File

@ -265,7 +265,7 @@ LLSocket::~LLSocket()
void LLSocket::setBlocking(S32 timeout)
{
// set up the socket options
ll_apr_warn_status(apr_socket_timeout_set(mSocket, timeout));
ll_apr_warn_status(apr_socket_timeout_set(mSocket, timeout)); // Sets both receive and send timeout SO_RCVTIMEO, SO_SNDTIMEO
ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_NONBLOCK, 0));
ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_SNDBUF, LL_SEND_BUFFER_SIZE));
ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_RCVBUF, LL_RECV_BUFFER_SIZE));

View File

@ -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(),
@ -473,7 +473,8 @@ static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataou
rv = apr_socket_send(apr_socket, dataout, &outlen);
if (APR_SUCCESS != rv)
{
LL_WARNS("Proxy") << "Error sending data to proxy control channel, status: " << rv << LL_ENDL;
char buf[MAX_STRING];
LL_WARNS("Proxy") << "Error sending data to proxy control channel, status: " << rv << " " << apr_strerror(rv, buf, MAX_STRING) << LL_ENDL;
ll_apr_warn_status(rv);
}
else if (expected_len != outlen)
@ -483,13 +484,16 @@ static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataou
rv = -1;
}
ms_sleep(1);
if (APR_SUCCESS == rv)
{
expected_len = maxinlen;
rv = apr_socket_recv(apr_socket, datain, &maxinlen);
if (rv != APR_SUCCESS)
{
LL_WARNS("Proxy") << "Error receiving data from proxy control channel, status: " << rv << LL_ENDL;
char buf[MAX_STRING];
LL_WARNS("Proxy") << "Error receiving data from proxy control channel, status: " << rv << " " << apr_strerror(rv, buf, MAX_STRING) << LL_ENDL;
ll_apr_warn_status(rv);
}
else if (expected_len < maxinlen)

View File

@ -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<bool> mHTTPProxyEnabled;
mutable LLAtomicBool mHTTPProxyEnabled;
// Mutex to protect shared members in non-main thread calls to applyProxySettings().
mutable LLMutex mProxyMutex;

View File

@ -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;

View File

@ -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();

View File

@ -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)

View File

@ -80,11 +80,11 @@ protected:
};
LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner):
mIncomingQueueMutex(gAPRPoolp)
mIncomingQueueMutex()
{
if(!sInstancesMutex)
{
sInstancesMutex = new LLMutex(gAPRPoolp);
sInstancesMutex = new LLMutex();
}
mOwner = owner;

View File

@ -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;

View File

@ -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;

View File

@ -157,7 +157,7 @@ void ft_close_cb(FT_Stream stream) {
}
#endif
BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback)
BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback, S32 face_n)
{
// Don't leak face objects. This is also needed to deal with
// changed font file names.
@ -168,40 +168,8 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v
}
int error;
#ifdef LL_WINDOWS
pFileStream = new llifstream(filename, std::ios::binary);
if (pFileStream->is_open())
{
std::streampos beg = pFileStream->tellg();
pFileStream->seekg(0, std::ios::end);
std::streampos end = pFileStream->tellg();
std::size_t file_size = end - beg;
pFileStream->seekg(0, std::ios::beg);
pFtStream = new LLFT_Stream();
pFtStream->base = 0;
pFtStream->pos = 0;
pFtStream->size = file_size;
pFtStream->descriptor.pointer = pFileStream;
pFtStream->read = ft_read_cb;
pFtStream->close = ft_close_cb;
FT_Open_Args args;
args.flags = FT_OPEN_STREAM;
args.stream = (FT_StreamRec*)pFtStream;
error = FT_Open_Face(gFTLibrary,
&args,
0,
&mFTFace);
}
else
{
delete pFileStream;
pFileStream = NULL;
return FALSE;
}
error = ftOpenFace(filename, face_n);
#else
error = FT_New_Face( gFTLibrary,
filename.c_str(),
@ -212,11 +180,7 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v
if (error)
{
#ifdef LL_WINDOWS
pFileStream->close();
delete pFileStream;
delete pFtStream;
pFileStream = NULL;
pFtStream = NULL;
clearFontStreams();
#endif
return FALSE;
}
@ -235,11 +199,7 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v
// Clean up freetype libs.
FT_Done_Face(mFTFace);
#ifdef LL_WINDOWS
pFileStream->close();
delete pFileStream;
delete pFtStream;
pFileStream = NULL;
pFtStream = NULL;
clearFontStreams();
#endif
mFTFace = NULL;
return FALSE;
@ -297,6 +257,78 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v
return TRUE;
}
S32 LLFontFreetype::getNumFaces(const std::string& filename)
{
if (mFTFace)
{
FT_Done_Face(mFTFace);
mFTFace = NULL;
}
S32 num_faces = 1;
#ifdef LL_WINDOWS
int error = ftOpenFace(filename, 0);
if (error)
{
return 0;
}
else
{
num_faces = mFTFace->num_faces;
}
FT_Done_Face(mFTFace);
clearFontStreams();
mFTFace = NULL;
#endif
return num_faces;
}
#ifdef LL_WINDOWS
S32 LLFontFreetype::ftOpenFace(const std::string& filename, S32 face_n)
{
S32 error = -1;
pFileStream = new llifstream(filename, std::ios::binary);
if (pFileStream->is_open())
{
std::streampos beg = pFileStream->tellg();
pFileStream->seekg(0, std::ios::end);
std::streampos end = pFileStream->tellg();
std::size_t file_size = end - beg;
pFileStream->seekg(0, std::ios::beg);
pFtStream = new LLFT_Stream();
pFtStream->base = 0;
pFtStream->pos = 0;
pFtStream->size = file_size;
pFtStream->descriptor.pointer = pFileStream;
pFtStream->read = ft_read_cb;
pFtStream->close = ft_close_cb;
FT_Open_Args args;
args.flags = FT_OPEN_STREAM;
args.stream = (FT_StreamRec*)pFtStream;
error = FT_Open_Face(gFTLibrary, &args, face_n, &mFTFace);
}
return error;
}
void LLFontFreetype::clearFontStreams()
{
if (pFileStream)
{
pFileStream->close();
}
delete pFileStream;
delete pFtStream;
pFileStream = NULL;
pFtStream = NULL;
}
#endif
void LLFontFreetype::setFallbackFonts(const font_vector_t &font)
{
mFallbackFonts = font;

View File

@ -84,7 +84,14 @@ public:
// is_fallback should be true for fallback fonts that aren't used
// to render directly (Unicode backup, primarily)
BOOL loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback);
BOOL loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback, S32 face_n = 0);
S32 getNumFaces(const std::string& filename);
#ifdef LL_WINDOWS
S32 ftOpenFace(const std::string& filename, S32 face_n);
void clearFontStreams();
#endif
typedef std::vector<LLPointer<LLFontFreetype> > font_vector_t;

View File

@ -89,14 +89,24 @@ void LLFontGL::destroyGL()
mFontFreetype->destroyGL();
}
BOOL LLFontGL::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback)
BOOL LLFontGL::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback, S32 face_n)
{
if(mFontFreetype == reinterpret_cast<LLFontFreetype*>(NULL))
{
mFontFreetype = new LLFontFreetype;
}
return mFontFreetype->loadFace(filename, point_size, vert_dpi, horz_dpi, components, is_fallback);
return mFontFreetype->loadFace(filename, point_size, vert_dpi, horz_dpi, components, is_fallback, face_n);
}
S32 LLFontGL::getNumFaces(const std::string& filename)
{
if (mFontFreetype == reinterpret_cast<LLFontFreetype*>(NULL))
{
mFontFreetype = new LLFontFreetype;
}
return mFontFreetype->getNumFaces(filename);
}
static LLTrace::BlockTimerStatHandle FTM_RENDER_FONTS("Fonts");

View File

@ -87,7 +87,9 @@ public:
void destroyGL();
BOOL loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, const S32 components, BOOL is_fallback);
BOOL loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, const S32 components, BOOL is_fallback, S32 face_n = 0);
S32 getNumFaces(const std::string& filename);
S32 render(const LLWString &text, S32 begin_offset,
const LLRect& rect,

View File

@ -44,6 +44,8 @@ using std::map;
bool font_desc_init_from_xml(LLXMLNodePtr node, LLFontDescriptor& desc);
bool init_from_xml(LLFontRegistry* registry, LLXMLNodePtr node);
const std::string MACOSX_FONT_PATH_LIBRARY = "/Library/Fonts/";
LLFontDescriptor::LLFontDescriptor():
mStyle(0)
{
@ -60,6 +62,16 @@ LLFontDescriptor::LLFontDescriptor(const std::string& name,
{
}
LLFontDescriptor::LLFontDescriptor(const std::string& name,
const std::string& size,
const U8 style,
const string_vec_t& file_names,
const string_vec_t& ft_collection_listections) :
LLFontDescriptor(name, size, style, file_names)
{
mFontCollectionsList = ft_collection_listections;
}
LLFontDescriptor::LLFontDescriptor(const std::string& name,
const std::string& size,
const U8 style):
@ -162,7 +174,7 @@ LLFontDescriptor LLFontDescriptor::normalize() const
if (removeSubString(new_name,"Italic"))
new_style |= LLFontGL::ITALIC;
return LLFontDescriptor(new_name,new_size,new_style,getFileNames());
return LLFontDescriptor(new_name,new_size,new_style,getFileNames(),getFontCollectionsList());
}
LLFontRegistry::LLFontRegistry(bool create_gl_textures)
@ -213,6 +225,7 @@ bool LLFontRegistry::parseFontInfo(const std::string& xml_filename)
success = success || init_succ;
}
}
//if (success)
// dump();
@ -260,6 +273,16 @@ bool font_desc_init_from_xml(LLXMLNodePtr node, LLFontDescriptor& desc)
{
std::string font_file_name = child->getTextContents();
desc.getFileNames().push_back(font_file_name);
if (child->hasAttribute("load_collection"))
{
BOOL col = FALSE;
child->getAttributeBOOL("load_collection", col);
if (col)
{
desc.getFontCollectionsList().push_back(font_file_name);
}
}
}
else if (child->hasName("os"))
{
@ -306,8 +329,15 @@ bool init_from_xml(LLFontRegistry* registry, LLXMLNodePtr node)
match_file_names.insert(match_file_names.begin(),
desc.getFileNames().begin(),
desc.getFileNames().end());
string_vec_t collections_list = match_desc->getFontCollectionsList();
collections_list.insert(collections_list.begin(),
desc.getFontCollectionsList().begin(),
desc.getFontCollectionsList().end());
LLFontDescriptor new_desc = *match_desc;
new_desc.getFileNames() = match_file_names;
new_desc.getFontCollectionsList() = collections_list;
registry->mFontMap.erase(*match_desc);
registry->mFontMap[new_desc] = NULL;
}
@ -393,6 +423,7 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
// Build list of font names to look for.
// Files specified for this font come first, followed by those from the default descriptor.
string_vec_t file_names = match_desc->getFileNames();
string_vec_t ft_collection_list = match_desc->getFontCollectionsList();
string_vec_t default_file_names;
LLFontDescriptor default_desc("default",s_template_string,0);
const LLFontDescriptor *match_default_desc = getMatchingFontDesc(default_desc);
@ -401,6 +432,9 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
file_names.insert(file_names.end(),
match_default_desc->getFileNames().begin(),
match_default_desc->getFileNames().end());
ft_collection_list.insert(ft_collection_list.end(),
match_default_desc->getFontCollectionsList().begin(),
match_default_desc->getFontCollectionsList().end());
}
// Add ultimate fallback list - generated dynamically on linux,
@ -433,39 +467,62 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
file_name_it != file_names.end();
++file_name_it)
{
LLFontGL *fontp = new LLFontGL;
std::string font_path = local_path + *file_name_it;
LLFontGL *fontp = NULL;
string_vec_t font_paths;
font_paths.push_back(local_path + *file_name_it);
font_paths.push_back(sys_path + *file_name_it);
#if LL_DARWIN
font_paths.push_back(MACOSX_FONT_PATH_LIBRARY + *file_name_it);
#endif
bool is_ft_collection = (std::find(ft_collection_list.begin(), ft_collection_list.end(), *file_name_it) != ft_collection_list.end());
// *HACK: Fallback fonts don't render, so we can use that to suppress
// creation of OpenGL textures for test apps. JC
BOOL is_fallback = !is_first_found || !mCreateGLTextures;
F32 extra_scale = (is_fallback)?fallback_scale:1.0;
if (!fontp->loadFace(font_path, extra_scale * point_size,
LLFontGL::sVertDPI, LLFontGL::sHorizDPI, 2, is_fallback))
F32 point_size_scale = extra_scale * point_size;
bool is_font_loaded = false;
for(string_vec_t::iterator font_paths_it = font_paths.begin();
font_paths_it != font_paths.end();
++font_paths_it)
{
font_path = sys_path + *file_name_it;
if (!fontp->loadFace(font_path, extra_scale * point_size,
LLFontGL::sVertDPI, LLFontGL::sHorizDPI, 2, is_fallback))
fontp = new LLFontGL;
S32 num_faces = is_ft_collection ? fontp->getNumFaces(*font_paths_it) : 1;
for (S32 i = 0; i < num_faces; i++)
{
LL_INFOS_ONCE("LLFontRegistry") << "Couldn't load font " << *file_name_it << " from path " << local_path << LL_ENDL;
delete fontp;
fontp = NULL;
if (fontp == NULL)
{
fontp = new LLFontGL;
}
if (fontp->loadFace(*font_paths_it, point_size_scale,
LLFontGL::sVertDPI, LLFontGL::sHorizDPI, 2, is_fallback, i))
{
is_font_loaded = true;
if (is_first_found)
{
result = fontp;
is_first_found = false;
}
else
{
fontlist.push_back(fontp->mFontFreetype);
delete fontp;
fontp = NULL;
}
}
else
{
delete fontp;
fontp = NULL;
}
}
if (is_font_loaded) break;
}
if(fontp)
if(!is_font_loaded)
{
if (is_first_found)
{
result = fontp;
is_first_found = false;
}
else
{
fontlist.push_back(fontp->mFontFreetype);
delete fontp;
fontp = NULL;
}
LL_INFOS_ONCE("LLFontRegistry") << "Couldn't load font " << *file_name_it << LL_ENDL;
delete fontp;
fontp = NULL;
}
}

View File

@ -40,6 +40,7 @@ public:
LLFontDescriptor();
LLFontDescriptor(const std::string& name, const std::string& size, const U8 style);
LLFontDescriptor(const std::string& name, const std::string& size, const U8 style, const string_vec_t& file_names);
LLFontDescriptor(const std::string& name, const std::string& size, const U8 style, const string_vec_t& file_names, const string_vec_t& font_collections);
LLFontDescriptor normalize() const;
bool operator<(const LLFontDescriptor& b) const;
@ -52,6 +53,8 @@ public:
void setSize(const std::string& size) { mSize = size; }
const std::vector<std::string>& getFileNames() const { return mFileNames; }
std::vector<std::string>& getFileNames() { return mFileNames; }
const std::vector<std::string>& getFontCollectionsList() const { return mFontCollectionsList; }
std::vector<std::string>& getFontCollectionsList() { return mFontCollectionsList; }
const U8 getStyle() const { return mStyle; }
void setStyle(U8 style) { mStyle = style; }
@ -59,6 +62,7 @@ private:
std::string mName;
std::string mSize;
string_vec_t mFileNames;
string_vec_t mFontCollectionsList;
U8 mStyle;
};

View File

@ -200,6 +200,7 @@ set(llui_HEADER_FILES
llresizehandle.h
llresmgr.h
llrngwriter.h
llsearchablecontrol.h
llsearcheditor.h
llscrollbar.h
llscrollcontainer.h

View File

@ -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();

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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)
{

View File

@ -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<Params, LLUICtrl::Params>
@ -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;

View File

@ -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

View File

@ -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<Params, LLF32UICtrl::Params>
@ -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();

View File

@ -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();
}

View File

@ -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 );

View File

@ -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);

View File

@ -275,7 +275,8 @@ typedef LLPointer<LLTextSegment> 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

View File

@ -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;
}

View File

@ -237,13 +237,9 @@ void LLUI::dirtyRect(LLRect rect)
void LLUI::setMousePositionScreen(S32 x, S32 y)
{
S32 screen_x, screen_y;
#if defined(LL_DARWIN)
screen_x = ll_round((F32)x);
screen_y = ll_round((F32)y);
#else
screen_x = ll_round((F32)x * getScaleFactor().mV[VX]);
screen_y = ll_round((F32)y * getScaleFactor().mV[VY]);
#endif
LLView::getWindow()->setCursorPosition(LLCoordGL(screen_x, screen_y).convert());
}

View File

@ -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;

View File

@ -32,7 +32,6 @@
#include <map>
#include <set>
#include "llapr.h"
#include "llpointer.h"
#include "llqueuedthread.h"

View File

@ -27,6 +27,7 @@
#include "linden_common.h"
#include "llapr.h" // thread-related functions
#include "llpidlock.h"
#include "lldir.h"
#include "llsd.h"

View File

@ -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++)

View File

@ -32,8 +32,6 @@
#include <map>
#include <set>
#include "llapr.h"
#include "llqueuedthread.h"
#include "llvfs.h"

View File

@ -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]);
}

View File

@ -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);

View File

@ -738,6 +738,17 @@ void LLWindowWin32::restore()
SetFocus(mWindowHandle);
}
bool destroy_window_handler(HWND &hWnd)
{
__try
{
return DestroyWindow(hWnd);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return false;
}
}
// close() destroys all OS-specific code associated with a window.
// Usually called from LLWindowManager::destroyWindow()
@ -811,7 +822,7 @@ void LLWindowWin32::close()
ShowWindow(mWindowHandle, SW_HIDE);
// This causes WM_DESTROY to be sent *immediately*
if (!DestroyWindow(mWindowHandle))
if (!destroy_window_handler(mWindowHandle))
{
OSMessageBox(mCallbacks->translateString("MBDestroyWinFailed"),
mCallbacks->translateString("MBShutdownErr"),

View File

@ -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<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<std::string, U32> settings_pair_t;
typedef std::vector<settings_pair_t> 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<LLControlVariable> LLControlGroup::getControl(const std::string& name)
{
if (mSettingsProfile)
{
incrCount(name);
}
ctrl_name_table_t::iterator iter = mNameTable.find(name);
return iter == mNameTable.end() ? LLPointer<LLControlVariable>() : iter->second;
}
@ -349,8 +368,14 @@ const std::string LLControlGroup::mTypeString[TYPE_COUNT] = { "U32"
};
LLControlGroup::LLControlGroup(const std::string& name)
: LLInstanceTracker<LLControlGroup, std::string>(name)
: LLInstanceTracker<LLControlGroup, std::string>(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<bool>(name);

View File

@ -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;
};

View File

@ -531,7 +531,12 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
}
// now we can set page zoom factor
mCEFLib->setPageZoom(message_in.getValueReal("factor"));
F32 factor = (F32)message_in.getValueReal("factor");
#if LL_DARWIN
//temporary fix for SL-10473: issue with displaying checkboxes on Mojave
factor*=1.001;
#endif
mCEFLib->setPageZoom(factor);
// Plugin gets to decide the texture parameters to use.
mDepth = 4;
@ -736,6 +741,10 @@ void MediaPluginCEF::receiveMessage(const char* message_string)
if (message_name == "set_page_zoom_factor")
{
F32 factor = (F32)message_in.getValueReal("factor");
#if LL_DARWIN
//temporary fix for SL-10473: issue with displaying checkboxes on Mojave
factor*=1.001;
#endif
mCEFLib->setPageZoom(factor);
}
if (message_name == "browse_stop")
@ -813,7 +822,8 @@ void MediaPluginCEF::keyEvent(dullahan::EKeyEvent key_event, LLSD native_key_dat
// adding new code below in unicodeInput means we don't send ascii chars
// here too or we get double key presses on a mac.
bool esc_key = (event_umodchars == 27);
if (esc_key || ((unsigned char)event_chars < 0x10 || (unsigned char)event_chars >= 0x7f ))
bool tab_key_up = (event_umodchars == 9) && (key_event == dullahan::EKeyEvent::KE_KEY_UP);
if ((esc_key || ((unsigned char)event_chars < 0x10 || (unsigned char)event_chars >= 0x7f )) && !tab_key_up)
{
mCEFLib->nativeKeyboardEventOSX(key_event, event_modifiers,
event_keycode, event_chars,

View File

@ -201,7 +201,6 @@ set(viewer_SOURCE_FILES
llexperiencelog.cpp
llexternaleditor.cpp
llface.cpp
llfacebookconnect.cpp
llfasttimerview.cpp
llfavoritesbar.cpp
llfeaturemanager.cpp
@ -245,7 +244,6 @@ set(viewer_SOURCE_FILES
llfloaterexperiencepicker.cpp
llfloaterexperienceprofile.cpp
llfloaterexperiences.cpp
llfloaterfacebook.cpp
llfloaterflickr.cpp
llfloaterfonttest.cpp
llfloatergesture.cpp
@ -276,6 +274,7 @@ set(viewer_SOURCE_FILES
llfloatermemleak.cpp
llfloatermodelpreview.cpp
llfloatermodeluploadbase.cpp
llfloatermyscripts.cpp
llfloaternamedesc.cpp
llfloaternotificationsconsole.cpp
llfloaternotificationstabbed.cpp
@ -543,6 +542,7 @@ set(viewer_SOURCE_FILES
llscrollingpanelparam.cpp
llscrollingpanelparambase.cpp
llsculptidsize.cpp
llsearchableui.cpp
llsearchcombobox.cpp
llsearchhistory.cpp
llsecapi.cpp
@ -826,7 +826,6 @@ set(viewer_HEADER_FILES
llexperiencelog.h
llexternaleditor.h
llface.h
llfacebookconnect.h
llfasttimerview.h
llfavoritesbar.h
llfeaturemanager.h
@ -870,7 +869,6 @@ set(viewer_HEADER_FILES
llfloaterexperiencepicker.h
llfloaterexperienceprofile.h
llfloaterexperiences.h
llfloaterfacebook.h
llfloaterflickr.h
llfloaterfonttest.h
llfloatergesture.h
@ -904,6 +902,7 @@ set(viewer_HEADER_FILES
llfloatermemleak.h
llfloatermodelpreview.h
llfloatermodeluploadbase.h
llfloatermyscripts.h
llfloaternamedesc.h
llfloaternotificationsconsole.h
llfloaternotificationstabbed.h
@ -1160,6 +1159,7 @@ set(viewer_HEADER_FILES
llscrollingpanelparam.h
llscrollingpanelparambase.h
llsculptidsize.h
llsearchableui.h
llsearchcombobox.h
llsearchhistory.h
llsecapi.h
@ -1620,6 +1620,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
@ -1874,6 +1875,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)
set_property(
TARGET ${VIEWER_BINARY_NAME}
PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
)
endif (NOT UNATTENDED)
if (PACKAGE)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/event_host.tar.bz2
@ -2105,7 +2115,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. 2018")
set(MACOSX_BUNDLE_NSMAIN_NIB_FILE "SecondLife.nib")
set(MACOSX_BUNDLE_NSPRINCIPAL_CLASS "NSApplication")

View File

@ -228,16 +228,6 @@
is_running_function="Floater.IsOpen"
is_running_parameters="snapshot"
/>
<command name="facebook"
available_in_toybox="true"
icon="Command_Facebook_Icon"
label_ref="Command_Facebook_Label"
tooltip_ref="Command_Facebook_Tooltip"
execute_function="Floater.ToggleOrBringToFront"
execute_parameters="facebook"
is_running_function="Floater.IsOpen"
is_running_parameters="facebook"
/>
<command name="flickr"
available_in_toybox="true"
icon="Command_Flickr_Icon"

View File

@ -11362,6 +11362,17 @@
<key>Value</key>
<integer>0</integer>
</map>
<key>MenuSearch</key>
<map>
<key>Comment</key>
<string>Show/hide 'Search menus' field</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>GroupListShowIcons</key>
<map>
<key>Comment</key>
@ -14090,6 +14101,17 @@
<key>Value</key>
<integer>1</integer>
</map>
<key>RegionCrossingInterpolationTime</key>
<map>
<key>Comment</key>
<string>How long to extrapolate object motion after crossing regions</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>VertexShaderEnable</key>
<map>
<key>Comment</key>

View File

@ -21,7 +21,6 @@
<command name="voice"/>
<command name="minimap"/>
<command name="snapshot"/>
<command name="facebook"/>
</left_toolbar>
<right_toolbar
button_display_mode="icons_only">

View File

@ -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:

View File

@ -742,7 +742,7 @@ BOOL LLAgent::getFlying() const
//-----------------------------------------------------------------------------
// setFlying()
//-----------------------------------------------------------------------------
void LLAgent::setFlying(BOOL fly)
void LLAgent::setFlying(BOOL fly, BOOL fail_sound)
{
if (isAgentAvatarValid())
{
@ -771,7 +771,10 @@ void LLAgent::setFlying(BOOL fly)
// parcel doesn't let you start fly
// gods can always fly
// and it's OK if you're already flying
make_ui_sound("UISndBadKeystroke");
if (fail_sound)
{
make_ui_sound("UISndBadKeystroke");
}
return;
}
if( !was_flying )

View File

@ -337,7 +337,7 @@ private:
//--------------------------------------------------------------------
public:
BOOL getFlying() const;
void setFlying(BOOL fly);
void setFlying(BOOL fly, BOOL fail_sound = FALSE);
static void toggleFlying();
static bool enableFlying();
BOOL canFly(); // Does this parcel allow you to fly?

View File

@ -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,14 @@ bool LLAppViewer::init()
// ForceAddressSize
updater.args.add(stringize(gSavedSettings.getU32("ForceAddressSize")));
#if !LL_RELEASE_FOR_DOWNLOAD && !LL_SEND_CRASH_REPORTS
// This is neither a release package, nor crash-reporting enabled test build
// Note: pointless to launch on Windows - it shouldn't expect secondlife-bin.exe
LL_WARNS("LLLeap") << "Launching without version checker" << 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 +2174,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();
}
@ -3158,6 +3164,10 @@ LLSD LLAppViewer::getViewerInfo() const
substitution["datetime"] = (S32)(gVFS ? gVFS->creationTime() : 0);
info["VFS_TIME"] = LLTrans::getString("AboutTime", substitution);
#if LL_DARWIN
info["HIDPI"] = gHiDPISupport;
#endif
// Libraries
info["J2C_VERSION"] = LLImageJ2C::getEngineInfo();
@ -3300,6 +3310,9 @@ std::string LLAppViewer::getViewerInfoString(bool default_string) const
}
support << "\n" << LLTrans::getString("AboutOGL", args, default_string);
support << "\n\n" << LLTrans::getString("AboutSettings", args, default_string);
#if LL_DARWIN
support << "\n" << LLTrans::getString("AboutOSXHiDPI", args, default_string);
#endif
support << "\n\n" << LLTrans::getString("AboutLibs", args, default_string);
if (info.has("COMPILER"))
{
@ -5450,7 +5463,8 @@ void LLAppViewer::resumeMainloopTimeout(const std::string& state, F32 secs)
{
if(secs < 0.0f)
{
secs = gSavedSettings.getF32("MainloopTimeoutDefault");
static LLCachedControl<F32> mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60);
secs = mainloop_timeout;
}
mMainloopTimeout->setTimeout(secs);
@ -5477,7 +5491,8 @@ void LLAppViewer::pingMainloopTimeout(const std::string& state, F32 secs)
{
if(secs < 0.0f)
{
secs = gSavedSettings.getF32("MainloopTimeoutDefault");
static LLCachedControl<F32> mainloop_timeout(gSavedSettings, "MainloopTimeoutDefault", 60);
secs = mainloop_timeout;
}
mMainloopTimeout->setTimeout(secs);

View File

@ -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"

View File

@ -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)

View File

@ -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);

View File

@ -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;
}

View File

@ -119,6 +119,7 @@ BOOL LLAvatarListItem::postBuild()
mIconPermissionEditTheirs->setVisible(false);
mSpeakingIndicator = getChild<LLOutputMonitorCtrl>("speaking_indicator");
mSpeakingIndicator->setChannelState(LLOutputMonitorCtrl::UNDEFINED_CHANNEL);
mInfoBtn = getChild<LLButton>("info_btn");
mProfileBtn = getChild<LLButton>("profile_btn");

View File

@ -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<LLChatMsgBox>("msg_text", false);
mMsgText->setContentTrusted(false);
mMsgText->setIsFriendCallback(LLAvatarActions::isFriend);
mMsgText->setText(std::string(""));

View File

@ -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);
}
//

View File

@ -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;

View File

@ -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<LLFolderViewFolder*>(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<LLConversationViewParticipant*>(*iter);
if (participant)
{
mSpeakingIndicator->setVisible(false);
}
LLConversationViewParticipant* participant = NULL;
items_t::const_iterator iter;
for (iter = getItemsBegin(); iter != getItemsEnd(); iter++)
{
participant = dynamic_cast<LLConversationViewParticipant*>(*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<LLConversationItemParticipant*>(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<LLConversationItemParticipant*>(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<LLConversationItem*>(getParentFolder()->getViewModelItem()) : NULL;
if (vmi)
LLFolderViewFolder *prnt = getParentFolder();
if (prnt)
{
addToSession(vmi->getUUID());
LLConversationItem* vmi = dynamic_cast<LLConversationItem*>(prnt->getViewModelItem());
if (vmi)
{
addToSession(vmi->getUUID());
}
LLConversationViewSession* session = dynamic_cast<LLConversationViewSession*>(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

Some files were not shown because too many files have changed in this diff Show More