Merge branch 'release/2026.01' into project/one-click

This commit is contained in:
Jonathan "Geenz" Goodman
2026-02-24 11:34:08 -05:00
43 changed files with 704 additions and 272 deletions
+7 -7
View File
@@ -2633,11 +2633,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>43c5f93517794aeade550e4266b959d1f0cfcb7f</string>
<string>72ed1f6d469a8ffaffd69be39b7af186d7c3b1d7</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.20-universal/webrtc-m137.7151.04.20-universal.17630578914-darwin64-17630578914.tar.zst</string>
<string>https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.22/webrtc-m137.7151.04.22.21966754211-darwin64-21966754211.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@@ -2647,11 +2647,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>efc5b176d878cfc16b8f82445d82ddb96815b6ab</string>
<string>b4d0c836d99491841c3816ff93bb2655a2817bd3</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.20-universal/webrtc-m137.7151.04.20-universal.17630578914-linux64-17630578914.tar.zst</string>
<string>https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.22/webrtc-m137.7151.04.22.21966754211-linux64-21966754211.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@@ -2661,11 +2661,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>1e36f100de32c7c71325497a672fb1659b3f206d</string>
<string>ab2bddd77b1568b22b50ead13c1c33da94f4d59a</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.20-universal/webrtc-m137.7151.04.20-universal.17630578914-windows64-17630578914.tar.zst</string>
<string>https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.22/webrtc-m137.7151.04.22.21966754211-windows64-21966754211.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@@ -2678,7 +2678,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>copyright</key>
<string>Copyright (c) 2011, The WebRTC project authors. All rights reserved.</string>
<key>version</key>
<string>m137.7151.04.20-universal.17630578914</string>
<string>m137.7151.04.22.21966754211</string>
<key>name</key>
<string>webrtc</string>
<key>vcs_branch</key>
+2
View File
@@ -101,6 +101,7 @@ set(llcommon_SOURCE_FILES
lluri.cpp
lluriparser.cpp
lluuid.cpp
llwatchdog.cpp
llworkerthread.cpp
hbxxh.cpp
u64.cpp
@@ -240,6 +241,7 @@ set(llcommon_HEADER_FILES
lluri.h
lluriparser.h
lluuid.h
llwatchdog.h
llwin32headers.h
llworkerthread.h
hbxxh.h
+12
View File
@@ -137,6 +137,18 @@ void llcoro::suspendUntilTimeout(float seconds)
suspendUntilEventOnWithTimeout(bogus, seconds, timedout);
}
void llcoro::suspendUntilNextFrame()
{
LLCoros::checkStop();
LLCoros::TempStatus st("waiting for next frame");
// Listen for the next event on the "mainloop" event pump.
// Once per frame we get mainloop.post(newFrame);
LLEventPumpOrPumpName mainloop_pump("mainloop");
// Wait for the next event (the event data is ignored).
suspendUntilEventOn(mainloop_pump);
}
namespace
{
+5
View File
@@ -84,6 +84,11 @@ void suspend();
*/
void suspendUntilTimeout(float seconds);
/**
* Yield control from a coroutine until the next mainloop's newFrame event.
*/
void suspendUntilNextFrame();
/**
* Post specified LLSD event on the specified LLEventPump, then suspend for a
* response on specified other LLEventPump. This is more than mere
+5 -1
View File
@@ -240,7 +240,11 @@ void LLThread::tryRun()
LL::WorkQueue::ptr_t main_queue = LL::WorkQueue::getInstance("mainloop");
main_queue->post(
// Bind the current exception, rethrow it in main loop.
[exc = std::current_exception()]() { std::rethrow_exception(exc); });
[exc = std::current_exception(), name = mName]()
{
LL_INFOS("THREAD") << "Rethrowing exception from thread " << name << LL_ENDL;
std::rethrow_exception(exc);
});
}
#endif // else LL_WINDOWS
}
@@ -24,11 +24,11 @@
* $/LicenseInfo$
*/
// Precompiled header
#include "linden_common.h"
#include "llviewerprecompiledheaders.h"
#include "llwatchdog.h"
#include "llthread.h"
#include "llappviewer.h"
constexpr U32 WATCHDOG_SLEEP_TIME_USEC = 1000000U;
@@ -67,7 +67,9 @@ private:
};
// LLWatchdogEntry
LLWatchdogEntry::LLWatchdogEntry()
LLWatchdogEntry::LLWatchdogEntry(const std::string& thread_name)
: mThreadName(thread_name)
, mThreadID(LLThread::currentID())
{
}
@@ -89,11 +91,16 @@ void LLWatchdogEntry::stop()
LLWatchdog::getInstance()->remove(this);
}
}
std::string LLWatchdogEntry::getThreadName() const
{
return mThreadName + llformat(": %d", mThreadID);
}
// LLWatchdogTimeout
const std::string UNINIT_STRING = "uninitialized";
LLWatchdogTimeout::LLWatchdogTimeout() :
LLWatchdogTimeout::LLWatchdogTimeout(const std::string& thread_name) :
LLWatchdogEntry(thread_name),
mTimeout(0.0f),
mPingState(UNINIT_STRING)
{
@@ -175,7 +182,7 @@ void LLWatchdog::remove(LLWatchdogEntry* e)
unlockThread();
}
void LLWatchdog::init()
void LLWatchdog::init(func_t set_error_state_callback)
{
if (!mSuspectsAccessMutex && !mTimer)
{
@@ -188,6 +195,7 @@ void LLWatchdog::init()
// start needs to use the mSuspectsAccessMutex
mTimer->start();
}
mCreateMarkerFnc = set_error_state_callback;
}
void LLWatchdog::cleanup()
@@ -241,17 +249,23 @@ void LLWatchdog::run()
{
mTimer->stop();
}
if (LLAppViewer::instance()->logoutRequestSent())
// Sets error marker file
mCreateMarkerFnc();
// Todo1: Warn user?
// Todo2: We probably want to report even if 5 seconds passed, just not error 'yet'.
std::string last_state = (*result)->getLastState();
if (last_state.empty())
{
LLAppViewer::instance()->createErrorMarker(LAST_EXEC_LOGOUT_FROZE);
LL_ERRS() << "Watchdog timer for thread " << (*result)->getThreadName()
<< " expired; assuming viewer is hung and crashing" << LL_ENDL;
}
else
{
LLAppViewer::instance()->createErrorMarker(LAST_EXEC_FROZE);
LL_ERRS() << "Watchdog timer for thread " << (*result)->getThreadName()
<< " expired with state: " << last_state
<< "; assuming viewer is hung and crashing" << LL_ENDL;
}
// Todo1: warn user?
// Todo2: We probably want to report even if 5 seconds passed, just not error 'yet'.
LL_ERRS() << "Watchdog timer expired; assuming viewer is hung and crashing" << LL_ENDL;
}
}
@@ -30,13 +30,17 @@
#ifndef LL_TIMER_H
#include "lltimer.h"
#endif
#include "llmutex.h"
#include "llsingleton.h"
#include <functional>
// LLWatchdogEntry is the interface used by the tasks that
// need to be watched.
class LLWatchdogEntry
{
public:
LLWatchdogEntry();
LLWatchdogEntry(const std::string &thread_name);
virtual ~LLWatchdogEntry();
// isAlive is accessed by the watchdog thread.
@@ -46,12 +50,19 @@ public:
virtual void reset() = 0;
virtual void start();
virtual void stop();
virtual std::string getLastState() const { return std::string(); }
typedef std::thread::id id_t;
std::string getThreadName() const;
private:
id_t mThreadID; // ID of the thread being watched
std::string mThreadName;
};
class LLWatchdogTimeout : public LLWatchdogEntry
{
public:
LLWatchdogTimeout();
LLWatchdogTimeout(const std::string& thread_name);
virtual ~LLWatchdogTimeout();
bool isAlive() const override;
@@ -63,6 +74,7 @@ public:
void setTimeout(F32 d);
void ping(std::string_view state);
const std::string& getState() {return mPingState; }
std::string getLastState() const override { return mPingState; }
private:
LLTimer mTimer;
@@ -81,10 +93,12 @@ public:
void add(LLWatchdogEntry* e);
void remove(LLWatchdogEntry* e);
void init();
typedef std::function<void()> func_t;
void init(func_t set_error_state_callback);
void run();
void cleanup();
private:
void lockThread();
void unlockThread();
@@ -94,6 +108,11 @@ private:
LLMutex* mSuspectsAccessMutex;
LLWatchdogTimerThread* mTimer;
U64 mLastClockCount;
// At the moment watchdog expects app to set markers in mCreateMarkerFnc,
// but technically can be used to set any error states or do some cleanup
// or show warnings.
func_t mCreateMarkerFnc;
};
#endif // LL_LLTHREADWATCHDOG_H
+6 -1
View File
@@ -216,10 +216,15 @@ void LL::WorkQueueBase::callWork(const Work& work)
LL_WARNS("LLCoros") << "Capturing and rethrowing uncaught exception in WorkQueueBase "
<< getKey() << LL_ENDL;
std::string name = getKey();
LL::WorkQueue::ptr_t main_queue = LL::WorkQueue::getInstance("mainloop");
main_queue->post(
// Bind the current exception, rethrow it in main loop.
[exc = std::current_exception()]() { std::rethrow_exception(exc); });
[exc = std::current_exception(), name]()
{
LL_INFOS("LLCoros") << "Rethrowing exception from WorkQueueBase::callWork " << name << LL_ENDL;
std::rethrow_exception(exc);
});
}
else
{
+5 -1
View File
@@ -530,7 +530,11 @@ namespace LL
reply,
// Bind the current exception to transport back to the
// originating WorkQueue. Once there, rethrow it.
[exc = std::current_exception()](){ std::rethrow_exception(exc); });
[exc = std::current_exception()]()
{
LL_INFOS("LLCoros") << "Rethrowing exception from WorkQueueBase::postTo" << LL_ENDL;
std::rethrow_exception(exc);
});
}
},
// if caller passed a TimePoint, pass it along to post()
+3
View File
@@ -1316,6 +1316,9 @@ const char* LLAssetStorage::getErrorString(S32 status)
case LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE:
return "Asset request: asset not found in database";
case LL_ERR_NO_CAP:
return "Asset request: region or asset capability not available";
case LL_ERR_EOF:
return "End of file";
+1
View File
@@ -57,6 +57,7 @@ const int LL_ERR_ASSET_REQUEST_FAILED = -1;
const int LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE = -3;
const int LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE = -4;
const int LL_ERR_INSUFFICIENT_PERMISSIONS = -5;
const int LL_ERR_NO_CAP = -6;
const int LL_ERR_PRICE_MISMATCH = -23018;
// *TODO: these typedefs are passed into the cache via a legacy C function pointer
+14
View File
@@ -4404,3 +4404,17 @@ bool LLContextMenu::addChild(LLView* view, S32 tab_group)
return addContextChild(view, tab_group);
}
void LLContextMenu::deleteAllChildren()
{
mHoverItem = nullptr;
LLMenuGL::deleteAllChildren();
}
void LLContextMenu::removeChild(LLView* ctrl)
{
if (ctrl == mHoverItem)
{
mHoverItem = nullptr;
}
LLMenuGL::removeChild(ctrl);
}
+2
View File
@@ -730,6 +730,8 @@ public:
virtual bool handleRightMouseUp ( S32 x, S32 y, MASK mask );
virtual bool addChild (LLView* view, S32 tab_group = 0);
/*virtual*/ void deleteAllChildren();
/*virtual*/ void removeChild(LLView* ctrl);
LLHandle<LLContextMenu> getHandle() { return getDerivedHandle<LLContextMenu>(); }
+2 -1
View File
@@ -814,6 +814,7 @@ LLWebRTCPeerConnectionImpl::~LLWebRTCPeerConnectionImpl()
{
mSignalingObserverList.clear();
mDataObserverList.clear();
mPeerConnectionFactory.release();
if (mPendingJobs > 0)
{
RTC_LOG(LS_ERROR) << __FUNCTION__ << "Destroying a connection that has " << std::to_string(mPendingJobs) << " unfinished jobs that might cause workers to crash";
@@ -877,7 +878,6 @@ void LLWebRTCPeerConnectionImpl::terminate()
}
mPendingJobs--;
});
mPeerConnectionFactory.release();
}
void LLWebRTCPeerConnectionImpl::setSignalingObserver(LLWebRTCSignalingObserver *observer) { mSignalingObserverList.emplace_back(observer); }
@@ -1004,6 +1004,7 @@ bool LLWebRTCPeerConnectionImpl::initializeConnection(const LLWebRTCPeerConnecti
}
webrtc::PeerConnectionInterface::RTCOfferAnswerOptions offerOptions;
this->AddRef(); // CreateOffer will deref this when it's done. Without this, the callbacks never get called.
mPeerConnection->CreateOffer(this, offerOptions);
mPendingJobs--;
});
+2
View File
@@ -205,6 +205,8 @@ public:
};
virtual S32 getRefreshRate() { return mRefreshRate; }
virtual void initWatchdog() {} // windows runs window as a thread and it needs a watchdog
protected:
LLWindow(LLWindowCallbacks* callbacks, bool fullscreen, U32 flags);
virtual ~LLWindow();
+64 -1
View File
@@ -49,6 +49,7 @@
#include "llthreadsafequeue.h"
#include "stringize.h"
#include "llframetimer.h"
#include "llwatchdog.h"
// System includes
#include <commdlg.h>
@@ -364,7 +365,8 @@ static LLMonitorInfo sMonitorInfo;
// the containing class a friend.
struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
{
static const int MAX_QUEUE_SIZE = 2048;
static constexpr int MAX_QUEUE_SIZE = 2048;
static constexpr F32 WINDOW_TIMEOUT_SEC = 90.f;
LLThreadSafeQueue<MSG> mMessageQueue;
@@ -426,6 +428,50 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
PostMessage(windowHandle, WM_POST_FUNCTION_, wparam, LPARAM(ptr));
}
// Call from main thread.
void initTimeout()
{
// post into thread's queue to avoid threading issues
post([this]()
{
if (!mWindowTimeout)
{
mWindowTimeout = std::make_unique<LLWatchdogTimeout>("WindowThread");
// supposed to be executed within run(),
// so no point checking if thread is alive
resumeTimeout("TimeoutInit");
}
});
}
private:
// These timeout related functions are strictly for the thread.
void resumeTimeout(std::string_view state)
{
if (mWindowTimeout)
{
mWindowTimeout->setTimeout(WINDOW_TIMEOUT_SEC);
mWindowTimeout->start(state);
}
}
void pauseTimeout()
{
if (mWindowTimeout)
{
mWindowTimeout->stop();
}
}
void pingTimeout(std::string_view state)
{
if (mWindowTimeout)
{
mWindowTimeout->setTimeout(WINDOW_TIMEOUT_SEC);
mWindowTimeout->ping(state);
}
}
public:
using FuncType = std::function<void()>;
// call GetMessage() and pull enqueue messages for later processing
HWND mWindowHandleThrd = NULL;
@@ -436,6 +482,8 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
bool mGLReady = false;
bool mGotGLBuffer = false;
LLAtomicBool mDeleteOnExit = false;
private:
std::unique_ptr<LLWatchdogTimeout> mWindowTimeout;
};
@@ -4595,6 +4643,11 @@ bool LLWindowWin32::getInputDevices(U32 device_type_filter,
return false;
}
void LLWindowWin32::initWatchdog()
{
mWindowThread->initTimeout();
}
F32 LLWindowWin32::getSystemUISize()
{
F32 scale_value = 1.f;
@@ -4732,6 +4785,8 @@ void LLWindowWin32::LLWindowWin32Thread::checkDXMem()
return;
}
pauseTimeout();
IDXGIFactory4* p_factory = nullptr;
HRESULT res = CreateDXGIFactory1(__uuidof(IDXGIFactory4), (void**)&p_factory);
@@ -4835,6 +4890,8 @@ void LLWindowWin32::LLWindowWin32Thread::checkDXMem()
}
mGotGLBuffer = true;
resumeTimeout("checkDXMem");
}
void LLWindowWin32::LLWindowWin32Thread::run()
@@ -4850,6 +4907,9 @@ void LLWindowWin32::LLWindowWin32Thread::run()
timeBeginPeriod(llclamp((U32) 1, tc.wPeriodMin, tc.wPeriodMax));
}
// Normally won't exist yet, but in case of re-init, make sure it's cleaned up
resumeTimeout("WindowThread");
while (! getQueue().done())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
@@ -4859,6 +4919,7 @@ void LLWindowWin32::LLWindowWin32Thread::run()
if (mWindowHandleThrd != 0)
{
pingTimeout("messages");
MSG msg;
BOOL status;
if (mhDCThrd == 0)
@@ -4886,6 +4947,7 @@ void LLWindowWin32::LLWindowWin32Thread::run()
{
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - Function Queue");
pingTimeout("queue");
logger.onChange("runPending()");
//process any pending functions
getQueue().runPending();
@@ -4900,6 +4962,7 @@ void LLWindowWin32::LLWindowWin32Thread::run()
#endif
}
pauseTimeout();
destroyWindow();
if (mDeleteOnExit)
+71 -70
View File
@@ -45,83 +45,82 @@ typedef void (*LLW32MsgCallback)(const MSG &msg);
class LLWindowWin32 : public LLWindow
{
public:
/*virtual*/ void show();
/*virtual*/ void hide();
/*virtual*/ void close();
/*virtual*/ bool getVisible();
/*virtual*/ bool getMinimized();
/*virtual*/ bool getMaximized();
/*virtual*/ bool maximize();
/*virtual*/ void minimize();
/*virtual*/ void restore();
/*virtual*/ bool getFullscreen();
/*virtual*/ bool getPosition(LLCoordScreen *position);
/*virtual*/ bool getSize(LLCoordScreen *size);
/*virtual*/ bool getSize(LLCoordWindow *size);
/*virtual*/ bool setPosition(LLCoordScreen position);
/*virtual*/ bool setSizeImpl(LLCoordScreen size);
/*virtual*/ bool setSizeImpl(LLCoordWindow size);
/*virtual*/ bool switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp = NULL);
/*virtual*/ void setTitle(const std::string title);
void show() override;
void hide() override;
void close() override;
bool getVisible() override;
bool getMinimized() override;
bool getMaximized() override;
bool maximize() override;
void minimize() override;
void restore() override;
bool getFullscreen();
bool getPosition(LLCoordScreen *position) override;
bool getSize(LLCoordScreen *size) override;
bool getSize(LLCoordWindow *size) override;
bool setPosition(LLCoordScreen position) override;
bool setSizeImpl(LLCoordScreen size) override;
bool setSizeImpl(LLCoordWindow size) override;
bool switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp = NULL) override;
void setTitle(const std::string title) override;
void* createSharedContext() override;
void makeContextCurrent(void* context) override;
void destroySharedContext(void* context) override;
/*virtual*/ void toggleVSync(bool enable_vsync);
/*virtual*/ bool setCursorPosition(LLCoordWindow position);
/*virtual*/ bool getCursorPosition(LLCoordWindow *position);
/*virtual*/ bool getCursorDelta(LLCoordCommon* delta);
/*virtual*/ bool isWrapMouse() const override { return !mAbsoluteCursorPosition; };
/*virtual*/ void showCursor();
/*virtual*/ void hideCursor();
/*virtual*/ void showCursorFromMouseMove();
/*virtual*/ void hideCursorUntilMouseMove();
/*virtual*/ bool isCursorHidden();
/*virtual*/ void updateCursor();
/*virtual*/ ECursorType getCursor() const;
/*virtual*/ void captureMouse();
/*virtual*/ void releaseMouse();
/*virtual*/ void setMouseClipping( bool b );
/*virtual*/ bool isClipboardTextAvailable();
/*virtual*/ bool pasteTextFromClipboard(LLWString &dst);
/*virtual*/ bool copyTextToClipboard(const LLWString &src);
/*virtual*/ void flashIcon(F32 seconds);
/*virtual*/ F32 getGamma();
/*virtual*/ bool setGamma(const F32 gamma); // Set the gamma
/*virtual*/ void setFSAASamples(const U32 fsaa_samples);
/*virtual*/ U32 getFSAASamples();
/*virtual*/ bool restoreGamma(); // Restore original gamma table (before updating gamma)
/*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; }
/*virtual*/ void gatherInput();
/*virtual*/ void delayInputProcessing();
/*virtual*/ void swapBuffers();
/*virtual*/ void restoreGLContext() {};
void toggleVSync(bool enable_vsync) override;
bool setCursorPosition(LLCoordWindow position) override;
bool getCursorPosition(LLCoordWindow *position) override;
bool getCursorDelta(LLCoordCommon* delta) override;
bool isWrapMouse() const override { return !mAbsoluteCursorPosition; };
void showCursor() override;
void hideCursor() override;
void showCursorFromMouseMove() override;
void hideCursorUntilMouseMove() override;
bool isCursorHidden() override;
void updateCursor() override;
ECursorType getCursor() const override;
void captureMouse() override;
void releaseMouse() override;
void setMouseClipping( bool b ) override;
bool isClipboardTextAvailable() override;
bool pasteTextFromClipboard(LLWString &dst) override;
bool copyTextToClipboard(const LLWString &src) override;
void flashIcon(F32 seconds) override;
F32 getGamma() override;
bool setGamma(const F32 gamma) override; // Set the gamma
void setFSAASamples(const U32 fsaa_samples) override;
U32 getFSAASamples() override;
bool restoreGamma() override; // Restore original gamma table (before updating gamma)
ESwapMethod getSwapMethod() override { return mSwapMethod; }
void gatherInput() override;
void delayInputProcessing() override;
void swapBuffers() override;
// handy coordinate space conversion routines
/*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordWindow *to);
/*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordScreen *to);
/*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordGL *to);
/*virtual*/ bool convertCoords(LLCoordGL from, LLCoordWindow *to);
/*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordGL *to);
/*virtual*/ bool convertCoords(LLCoordGL from, LLCoordScreen *to);
bool convertCoords(LLCoordScreen from, LLCoordWindow *to) override;
bool convertCoords(LLCoordWindow from, LLCoordScreen *to) override;
bool convertCoords(LLCoordWindow from, LLCoordGL *to) override;
bool convertCoords(LLCoordGL from, LLCoordWindow *to) override;
bool convertCoords(LLCoordScreen from, LLCoordGL *to) override;
bool convertCoords(LLCoordGL from, LLCoordScreen *to) override;
/*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions);
/*virtual*/ F32 getNativeAspectRatio();
/*virtual*/ F32 getPixelAspectRatio();
/*virtual*/ void setNativeAspectRatio(F32 ratio) { mOverrideAspectRatio = ratio; }
LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) override;
F32 getNativeAspectRatio() override;
F32 getPixelAspectRatio() override;
void setNativeAspectRatio(F32 ratio) override { mOverrideAspectRatio = ratio; }
/*virtual*/ bool dialogColorPicker(F32 *r, F32 *g, F32 *b );
bool dialogColorPicker(F32 *r, F32 *g, F32 *b ) override;
/*virtual*/ void *getPlatformWindow();
/*virtual*/ void bringToFront();
/*virtual*/ void focusClient();
void *getPlatformWindow() override;
void bringToFront() override;
void focusClient() override;
/*virtual*/ void allowLanguageTextInput(LLPreeditor *preeditor, bool b);
/*virtual*/ void setLanguageTextInput( const LLCoordGL & pos );
/*virtual*/ void updateLanguageTextInputArea();
/*virtual*/ void interruptLanguageTextInput();
/*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async);
void allowLanguageTextInput(LLPreeditor *preeditor, bool b) override;
void setLanguageTextInput( const LLCoordGL & pos ) override;
void updateLanguageTextInputArea() override;
void interruptLanguageTextInput() override;
void spawnWebBrowser(const std::string& escaped_url, bool async) override;
/*virtual*/ F32 getSystemUISize();
F32 getSystemUISize() override;
LLWindowCallbacks::DragNDropResult completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, LLWindowCallbacks::DragNDropAction action, const std::string url );
@@ -129,14 +128,16 @@ public:
static std::vector<std::string> getDynamicFallbackFontList();
static void setDPIAwareness();
/*virtual*/ void* getDirectInput8();
/*virtual*/ bool getInputDevices(U32 device_type_filter,
void* getDirectInput8() override;
bool getInputDevices(U32 device_type_filter,
std::function<bool(std::string&, LLSD&, void*)> osx_callback,
void* win_callback,
void* userdata);
void* userdata) override;
U32 getRawWParam() { return mRawWParam; }
void initWatchdog() override;
protected:
LLWindowWin32(LLWindowCallbacks* callbacks,
const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags,
-2
View File
@@ -738,7 +738,6 @@ set(viewer_SOURCE_FILES
llvovolume.cpp
llvowater.cpp
llvowlsky.cpp
llwatchdog.cpp
llwearableitemslist.cpp
llwearablelist.cpp
llweb.cpp
@@ -1417,7 +1416,6 @@ set(viewer_HEADER_FILES
llvovolume.h
llvowater.h
llvowlsky.h
llwatchdog.h
llwearableitemslist.h
llwearablelist.h
llweb.h
+10 -10
View File
@@ -641,7 +641,7 @@
<key>Type</key>
<string>String</string>
<key>Value</key>
<string>http://lecs-viewer-web-components.s3.amazonaws.com/v3.0/[GRID_LOWERCASE]/vawp/index.html</string>
<string>https://lecs-viewer-web-components.s3.amazonaws.com/v3.0/[GRID_LOWERCASE]/vawp/index.html</string>
</map>
<!--AvatarBakedTextureUploadTimeout is in use by QA-->
<key>AvatarBakedTextureUploadTimeout</key>
@@ -2467,7 +2467,7 @@
<key>Type</key>
<string>String</string>
<key>Value</key>
<string>http://lecs-viewer-web-components.s3.amazonaws.com/v3.0/[GRID_LOWERCASE]/guide.html</string>
<string>https://lecs-viewer-web-components.s3.amazonaws.com/v3.0/[GRID_LOWERCASE]/guide.html</string>
</map>
<key>DisableCameraConstraints</key>
<map>
@@ -2775,7 +2775,7 @@
<key>Type</key>
<string>String</string>
<key>Value</key>
<string>http://events.[GRID]/viewer/embed/event/[EVENT_ID]</string>
<string>https://events.[GRID]/viewer/embed/event/[EVENT_ID]</string>
</map>
<key>MainWorkTime</key>
<map>
@@ -3432,7 +3432,7 @@
<key>Type</key>
<string>String</string>
<key>Value</key>
<string>http://viewer-help.secondlife.com/[LANGUAGE]/[CHANNEL]/[VERSION]/[TOPIC][DEBUG_MODE]</string>
<string>https://viewer-help.secondlife.com/[LANGUAGE]/[CHANNEL]/[VERSION]/[TOPIC][DEBUG_MODE]</string>
</map>
<key>HowToHelpURL</key>
<map>
@@ -3443,7 +3443,7 @@
<key>Type</key>
<string>String</string>
<key>Value</key>
<string>http://lecs-viewer-web-components.s3.amazonaws.com/v3.0/[GRID_LOWERCASE]/howto/index.html</string>
<string>https://lecs-viewer-web-components.s3.amazonaws.com/v3.0/[GRID_LOWERCASE]/howto/index.html</string>
</map>
<key>HomeSidePanelURL</key>
<map>
@@ -4059,7 +4059,7 @@
<key>Type</key>
<string>String</string>
<key>Value</key>
<string>http://wiki.secondlife.com/wiki/[LSL_STRING]</string>
<string>https://wiki.secondlife.com/wiki/[LSL_STRING]</string>
</map>
<key>LSLFontSizeName</key>
<map>
@@ -4511,7 +4511,7 @@
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>30.0</real>
<real>60.0</real>
</map>
<key>MapScale</key>
<map>
@@ -7345,7 +7345,7 @@
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>32.0</real>
<real>48.0</real>
</map>
<key>RenderCPUBasis</key>
<map>
@@ -9068,7 +9068,7 @@
<key>Comment</key>
<string>Show reflection probes in the transparency debug view</string>
<key>Persist</key>
<integer>1</integer>
<integer>0</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
@@ -14720,7 +14720,7 @@
<key>Type</key>
<string>String</string>
<key>Value</key>
<string>http://common-flash-secondlife-com.s3.amazonaws.com/viewer/v2.6/agni/404.html</string>
<string>https://common-flash-secondlife-com.s3.amazonaws.com/viewer/v2.6/agni/404.html</string>
</map>
<key>OpenIMOnVoice</key>
<map>
+6 -1
View File
@@ -1060,7 +1060,12 @@ void AISUpdate::checkTimeout()
{
if (mTimer.hasExpired())
{
llcoro::suspend();
// If we are taking too long, don't starve other tasks,
// yield to mainloop.
// If we use normal suspend(), there will be a chance of
// waking up from other suspends, before main coro had
// a chance, so wait for a frame tick instead.
llcoro::suspendUntilNextFrame();
LLCoros::checkStop();
mTimer.setTimerExpirySec(AIS_EXPIRY_SECONDS);
}
+61 -7
View File
@@ -1194,7 +1194,7 @@ bool LLAppViewer::init()
/*----------------------------------------------------------------------*/
// nat 2016-06-29 moved the following here from the former mainLoop().
mMainloopTimeout = new LLWatchdogTimeout();
mMainloopTimeout = new LLWatchdogTimeout("mainloop");
// Create IO Pump to use for HTTP Requests.
gServicePump = new LLPumpIO(gAPRPoolp);
@@ -1301,6 +1301,7 @@ bool LLAppViewer::frame()
bool LLAppViewer::doFrame()
{
resumeMainloopTimeout("Main:doFrameStart");
#ifdef LL_DISCORD
{
LL_PROFILE_ZONE_NAMED("discord_callbacks");
@@ -1384,12 +1385,14 @@ bool LLAppViewer::doFrame()
{
LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df mainloop");
pingMainloopTimeout("df mainloop");
// canonical per-frame event
mainloop.post(newFrame);
}
{
LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df suspend");
pingMainloopTimeout("df suspend");
// give listeners a chance to run
llcoro::suspend();
// if one of our coroutines threw an uncaught exception, rethrow it now
@@ -1425,6 +1428,7 @@ bool LLAppViewer::doFrame()
{
{
LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df pauseMainloopTimeout");
pingMainloopTimeout("df idle"); // So that it will be aware of last state.
pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds!
}
@@ -1436,7 +1440,7 @@ bool LLAppViewer::doFrame()
{
LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df resumeMainloopTimeout");
resumeMainloopTimeout();
resumeMainloopTimeout("df idle");
}
}
@@ -1451,7 +1455,7 @@ bool LLAppViewer::doFrame()
}
disconnectViewer();
resumeMainloopTimeout();
resumeMainloopTimeout("df snapshot n disconnect");
}
// Render scene.
@@ -1592,17 +1596,20 @@ bool LLAppViewer::doFrame()
if (LLApp::isExiting())
{
pingMainloopTimeout("Main:qSnapshot");
// Save snapshot for next time, if we made it through initialization
if (STATE_STARTED == LLStartUp::getStartupState())
{
saveFinalSnapshot();
}
pingMainloopTimeout("Main:TerminateVoice");
if (LLVoiceClient::instanceExists())
{
LLVoiceClient::getInstance()->terminate();
}
pingMainloopTimeout("Main:TerminatePump");
delete gServicePump;
gServicePump = NULL;
@@ -1611,6 +1618,11 @@ bool LLAppViewer::doFrame()
LL_INFOS() << "Exiting main_loop" << LL_ENDL;
}
}LLPerfStats::StatsRecorder::endFrame();
// Not viewer's fault if something outside frame
// pauses viewer (ex: macOS doesn't call oneFrame),
// so stop tracking on exit.
pauseMainloopTimeout();
LL_PROFILER_FRAME_END;
return ! LLApp::isRunning();
@@ -2265,7 +2277,22 @@ void errorHandler(const std::string& title_string, const std::string& message_st
}
if (!message_string.empty())
{
OSMessageBox(message_string, title_string.empty() ? LLTrans::getString("MBFatalError") : title_string, OSMB_OK);
if (on_main_thread())
{
// Prevent watchdog from killing us while dialog is up.
// Can't do pauseMainloopTimeout, since this may be called
// from threads and we are not going to need watchdog now.
LLAppViewer::instance()->pauseMainloopTimeout();
// todo: might want to have non-crashing timeout for OOM cases
// and needs a way to pause main loop.
OSMessageBox(message_string, title_string.empty() ? LLTrans::getString("MBFatalError") : title_string, OSMB_OK);
LLAppViewer::instance()->resumeMainloopTimeout();
}
else
{
OSMessageBox(message_string, title_string.empty() ? LLTrans::getString("MBFatalError") : title_string, OSMB_OK);
}
}
}
@@ -3128,7 +3155,18 @@ bool LLAppViewer::initWindow()
if (use_watchdog)
{
LLWatchdog::getInstance()->init();
LLWatchdog::getInstance()->init([]()
{
LLAppViewer* app = LLAppViewer::instance();
if (app->logoutRequestSent())
{
app->createErrorMarker(LAST_EXEC_LOGOUT_FROZE);
}
else
{
app->createErrorMarker(LAST_EXEC_FROZE);
}
});
}
LLNotificationsUI::LLNotificationManager::getInstance();
@@ -4108,6 +4146,7 @@ void LLAppViewer::requestQuit()
return;
}
pingMainloopTimeout("Main:qMetrics");
// Try to send metrics back to the grid
metricsSend(!gDisconnected);
@@ -4123,6 +4162,7 @@ void LLAppViewer::requestQuit()
LLHUDManager::getInstance()->sendEffects();
effectp->markDead() ;//remove it.
pingMainloopTimeout("Main:qFloaters");
// Attempt to close all floaters that might be
// editing things.
if (gFloaterView)
@@ -4131,6 +4171,7 @@ void LLAppViewer::requestQuit()
gFloaterView->closeAllChildren(true);
mClosingFloaters = true;
}
pingMainloopTimeout("Main:qStats");
// Send preferences once, when exiting
bool include_preferences = true;
@@ -4138,6 +4179,7 @@ void LLAppViewer::requestQuit()
gLogoutTimer.reset();
mQuitRequested = true;
pingMainloopTimeout("Main:LoggingOut");
}
static bool finish_quit(const LLSD& notification, const LLSD& response)
@@ -5418,6 +5460,7 @@ void LLAppViewer::outOfMemorySoftQuit()
LLLFSThread::sLocal->pause();
gLogoutTimer.reset();
mQuitRequested = true;
destroyMainloopTimeout();
LLError::LLUserWarningMsg::showOutOfMemory();
}
@@ -5789,7 +5832,7 @@ void LLAppViewer::initMainloopTimeout(std::string_view state)
{
if (!mMainloopTimeout)
{
mMainloopTimeout = new LLWatchdogTimeout();
mMainloopTimeout = new LLWatchdogTimeout("mainloop");
resumeMainloopTimeout(state);
}
}
@@ -5834,10 +5877,16 @@ void LLAppViewer::pingMainloopTimeout(std::string_view state)
F32 LLAppViewer::getMainloopTimeoutSec() const
{
if (isQuitting() || mQuitRequested)
{
constexpr F32 QUITTING_SECONDS = 240.f;
return QUITTING_SECONDS;
}
if (LLStartUp::getStartupState() == STATE_STARTED
&& gAgent.getTeleportState() == LLAgent::TELEPORT_NONE)
{
static LLCachedControl<F32> mainloop_started(gSavedSettings, "MainloopTimeoutStarted", 30.f);
// consider making this value match 'disconnected' timout.
static LLCachedControl<F32> mainloop_started(gSavedSettings, "MainloopTimeoutStarted", 60.f);
return mainloop_started();
}
else
@@ -5851,6 +5900,11 @@ void LLAppViewer::handleLoginComplete()
{
gLoggedInTime.start();
initMainloopTimeout("Mainloop Init");
LLWindow* viewer_window = gViewerWindow->getWindow();
if (viewer_window) // in case of a headless client
{
viewer_window->initWatchdog();
}
// Store some data to DebugInfo in case of a freeze.
gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::instance().getChannel();
+39 -19
View File
@@ -56,6 +56,7 @@ namespace Details
private:
void eventPollCoro(std::string url);
void handleMessage(const std::string& msg_name, const LLSD& body);
void handleMessage(const LLSD &content);
bool mDone;
@@ -95,21 +96,23 @@ namespace Details
mSenderIp = sender.getIPandPort();
}
void LLEventPollImpl::handleMessage(const std::string &msg_name, const LLSD &body)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_APP;
LLSD message;
message["sender"] = mSenderIp;
message["body"] = body;
LLMessageSystem::dispatch(msg_name, message);
}
void LLEventPollImpl::handleMessage(const LLSD& content)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_APP;
std::string msg_name = content["message"].asString();
LLSD message;
try
{
message["sender"] = mSenderIp;
message["body"] = content["body"];
}
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS("LLCoros") << "Bad memory allocation on message: " << msg_name << LL_ENDL;
}
message["sender"] = mSenderIp;
message["body"] = content["body"];
LLMessageSystem::dispatch(msg_name, message);
}
@@ -194,7 +197,7 @@ namespace Details
break;
}
LLSD httpResults = result["http_result"];
LLSD &httpResults = result["http_result"];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
if (!status)
@@ -299,7 +302,7 @@ namespace Details
}
acknowledge = result["id"];
LLSD events = result["events"];
LLSD &events = result["events"];
if (acknowledge.isUndefined())
{
@@ -310,20 +313,37 @@ namespace Details
LL_DEBUGS("LLEventPollImpl") << " <" << counter << "> " << events.size() << "events (id " << acknowledge << ")" << LL_ENDL;
LLSD::array_const_iterator i = events.beginArray();
LLSD::array_const_iterator end = events.endArray();
LLSD::array_iterator i = events.beginArray();
LLSD::array_iterator end = events.endArray();
for (; i != end; ++i)
{
if (i->has("message"))
{
if (main_queue)
{ // shuttle to a sensible spot in the main thread instead
{
// Shuttle copy to a sensible spot in the main thread instead
// of wherever this coroutine happens to be executing
const LLSD& msg = *i;
main_queue->post([this, msg]()
LL::WorkQueue::Work work;
{
// LLSD is too smart for it's own good and may act like a smart
// pointer for the content of (*i), so instead of passing (*i)
// pass a prepared name and move ownership of "body",
// as we are not going to need "body" anywhere else.
std::string msg_name = (*i)["message"].asString();
// WARNING: This is a shallow copy!
// If something still retains the data (like in httpAdapter?) this might still
// result in a crash, if it does appear to be the case, make a deep copy or
// convert data to string and pass that string.
const LLSD body = (*i)["body"];
(*i)["body"].clear();
work = [this, msg_name, body]()
{
handleMessage(msg);
});
handleMessage(msg_name, body);
};
}
main_queue->post(work);
}
else
{
+6 -2
View File
@@ -46,9 +46,13 @@ LLExternalEditor::EErrorCode LLExternalEditor::setCommand(const std::string& env
{
LL_INFOS() << "Editor command is empty or not set, falling back to OS open handler" << LL_ENDL;
#if LL_WINDOWS
static const std::string os_cmd = "%SystemRoot%\\explorer.exe \"%s\"";
std::string os_cmd = LLStringUtil::getenv("SystemRoot", "");
if (!os_cmd.empty())
{
os_cmd.append("\\explorer.exe \"%s\"");
}
#elif LL_DARWIN
static const std::string os_cmd = "/usr/bin/open \"%s\"";
static const std::string os_cmd = "/usr/bin/open -t \"%s\"";
#elif LL_LINUX
static const std::string os_cmd = "/usr/bin/xdg-open \"%s\"";
#endif
+3 -1
View File
@@ -495,7 +495,9 @@ bool LLFeatureManager::loadGPUClass()
{
mGPUClass = GPU_CLASS_2;
}
else if (gbps <= class1_gbps*4.f)
else if ((gbps <= class1_gbps*4.f)
// Cap silicon's GPUs at med+ as they have high throughput, low capability
|| gGLManager.mIsApple)
{
mGPUClass = GPU_CLASS_3;
}
+16
View File
@@ -1735,6 +1735,22 @@ void LLFloaterPreference::onChangeMaturity()
|| sim_access == SIM_ACCESS_ADULT);
getChild<LLIconCtrl>("rating_icon_adult")->setVisible(sim_access == SIM_ACCESS_ADULT);
// Update Legacy Search maturity settings
bool can_access_mature = gAgent.canAccessMature();
bool can_access_adult = gAgent.canAccessAdult();
if (!can_access_mature)
{
gSavedSettings.setBOOL("ShowMatureSims", false);
gSavedSettings.setBOOL("ShowMatureLand", false);
gSavedSettings.setBOOL("ShowMatureClassifieds", false);
}
if (!can_access_adult)
{
gSavedSettings.setBOOL("ShowAdultSims", false);
gSavedSettings.setBOOL("ShowAdultLand", false);
gSavedSettings.setBOOL("ShowAdultClassifieds", false);
}
}
void LLFloaterPreference::onChangeComplexityMode(const LLSD& newvalue)
+39 -27
View File
@@ -903,6 +903,39 @@ private:
};
F32 shader_timer_benchmark(std::vector<LLRenderTarget> & dest, TextureHolder & texHolder, U32 textures_count, LLVertexBuffer * buff, F32 &seconds)
{
// run GPU timer benchmark
//number of samples to take
const S32 samples = 64;
{
ShaderProfileHelper initProfile;
dest[0].bindTarget();
gBenchmarkProgram.bind();
for (S32 c = 0; c < samples; ++c)
{
for (U32 i = 0; i < textures_count; ++i)
{
texHolder.bind(i);
buff->setBuffer();
buff->drawArrays(LLRender::TRIANGLES, 0, 3);
}
}
gBenchmarkProgram.unbind();
dest[0].flush();
}
F32 ms = gBenchmarkProgram.mTimeElapsed / 1000000.f;
seconds = ms / 1000.f;
F64 samples_drawn = (F64)gBenchmarkProgram.mSamplesDrawn;
F64 gpixels_drawn = samples_drawn / 1000000000.0;
F32 samples_sec = (F32)(gpixels_drawn / seconds);
return samples_sec * 4; // 4 bytes per sample
}
//-----------------------------------------------------------------------------
// gpu_benchmark()
// returns measured memory bandwidth of GPU in gigabytes per second
@@ -944,9 +977,6 @@ F32 gpu_benchmark()
//number of textures
const U32 count = 32;
//number of samples to take
const S32 samples = 64;
//time limit, allocation operations shouldn't take longer then 30 seconds, same for actual benchmark.
const F32 time_limit = 30;
@@ -1036,33 +1066,15 @@ F32 gpu_benchmark()
LLGLSLShader::unbind();
// run GPU timer benchmark
{
ShaderProfileHelper initProfile;
dest[0].bindTarget();
gBenchmarkProgram.bind();
for (S32 c = 0; c < samples; ++c)
{
for (U32 i = 0; i < count; ++i)
{
texHolder.bind(i);
buff->setBuffer();
buff->drawArrays(LLRender::TRIANGLES, 0, 3);
}
}
gBenchmarkProgram.unbind();
dest[0].flush();
}
// run GPU timer benchmark twice
F32 seconds = 0;
F32 gbps = shader_timer_benchmark(dest, texHolder, count, buff.get(), seconds);
F32 ms = gBenchmarkProgram.mTimeElapsed/1000000.f;
F32 seconds = ms/1000.f;
LL_INFOS("Benchmark") << "Memory bandwidth, 1st run is " << llformat("%.3f", gbps) << " GB/sec according to ARB_timer_query, total time " << seconds << " seconds" << LL_ENDL;
F64 samples_drawn = (F64)gBenchmarkProgram.mSamplesDrawn;
F64 gpixels_drawn = samples_drawn / 1000000000.0;
F32 samples_sec = (F32)(gpixels_drawn/seconds);
F32 gbps = samples_sec*4; // 4 bytes per sample
gbps = shader_timer_benchmark(dest, texHolder, count, buff.get(), seconds);
LL_INFOS("Benchmark") << "Memory bandwidth is " << llformat("%.3f", gbps) << " GB/sec according to ARB_timer_query, total time " << seconds << " seconds" << LL_ENDL;
LL_INFOS("Benchmark") << "Memory bandwidth, final run is " << llformat("%.3f", gbps) << " GB/sec according to ARB_timer_query, total time " << seconds << " seconds" << LL_ENDL;
return gbps;
}
+8 -1
View File
@@ -1860,7 +1860,14 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action)
{
LLVector3d global_pos;
landmark->getGlobalPos(global_pos);
LLLandmarkActions::getSLURLfromPosGlobal(global_pos, &copy_slurl_to_clipboard_callback_inv, true);
if (!global_pos.isExactlyZero())
{
LLLandmarkActions::getSLURLfromPosGlobal(global_pos, &copy_slurl_to_clipboard_callback_inv, true);
}
else
{
LLNotificationsUtil::add("LandmarkLocationUnknown");
}
}
}
}
+14 -7
View File
@@ -338,14 +338,21 @@ void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata)
{
LLVector3d global_pos;
landmark->getGlobalPos(global_pos);
boost::function<void(std::string& slurl)> copy_slurl_to_clipboard_cb = [](const std::string& slurl)
if (!global_pos.isExactlyZero())
{
gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(slurl));
LLSD args;
args["SLURL"] = slurl;
LLNotificationsUtil::add("CopySLURL", args);
};
LLLandmarkActions::getSLURLfromPosGlobal(global_pos, copy_slurl_to_clipboard_cb, true);
boost::function<void(std::string& slurl)> copy_slurl_to_clipboard_cb = [](const std::string& slurl)
{
gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(slurl));
LLSD args;
args["SLURL"] = slurl;
LLNotificationsUtil::add("CopySLURL", args);
};
LLLandmarkActions::getSLURLfromPosGlobal(global_pos, copy_slurl_to_clipboard_cb, true);
}
else
{
LLNotificationsUtil::add("LandmarkLocationUnknown");
}
};
LLLandmark* landmark = LLLandmarkActions::getLandmark(mUUIDs.front(), copy_slurl_cb);
if (landmark)
+89 -7
View File
@@ -80,6 +80,40 @@ public:
}
};
class LLFetchFirstLandmarkByPos : public LLInventoryCollectFunctor
{
private:
LLVector3d mPos;
bool mFound = false;
public:
LLFetchFirstLandmarkByPos(const LLVector3d& pos) :
mPos(pos), mFound(false)
{
}
/*virtual*/ bool operator()(LLInventoryCategory* cat, LLInventoryItem* item)
{
if (mFound || !item || item->getType() != LLAssetType::AT_LANDMARK)
return false;
LLLandmark* landmark = gLandmarkList.getAsset(item->getAssetUUID());
if (!landmark) // the landmark not been loaded yet
return false;
LLVector3d landmark_global_pos;
if (!landmark->getGlobalPos(landmark_global_pos))
return false;
//we have to round off each coordinates to compare positions properly
mFound = ll_round(mPos.mdV[VX]) == ll_round(landmark_global_pos.mdV[VX])
&& ll_round(mPos.mdV[VY]) == ll_round(landmark_global_pos.mdV[VY])
&& ll_round(mPos.mdV[VZ]) == ll_round(landmark_global_pos.mdV[VZ]);
return mFound;
}
// only care about first found landmark, so stop when found
/*virtual*/ bool exceedsLimit() { return mFound; }
};
class LLFetchLandmarksByName : public LLInventoryCollectFunctor
{
private:
@@ -155,6 +189,9 @@ public:
mFounded = LLViewerParcelMgr::getInstance()->inAgentParcel(landmark_global_pos);
return mFounded;
}
// only care about first found landmark, so stop when found
/*virtual*/ bool exceedsLimit() { return mFounded; }
};
static void fetch_landmarks(LLInventoryModel::cat_array_t& cats,
@@ -197,23 +234,61 @@ bool LLLandmarkActions::landmarkAlreadyExists()
//static
bool LLLandmarkActions::hasParcelLandmark()
{
static LLUUID sLastItemID;
static S32 sLastFrame = -1;
if (sLastItemID.notNull())
{
LLInventoryItem* item = gInventory.getItem(sLastItemID);
if (item)
{
LLLandmark* landmark = gLandmarkList.getAsset(item->getAssetUUID());
if (landmark)
{
LLVector3d landmark_global_pos;
if (landmark->getGlobalPos(landmark_global_pos)
&& LLViewerParcelMgr::getInstance()->inAgentParcel(landmark_global_pos))
{
return true;
}
}
}
// Cached landmark does not match current parcel anymore,
// repeat inventory search to find a replacement landmark
// or to make sure there are none.
sLastItemID.setNull();
sLastFrame = -1;
}
if (sLastFrame == LLFrameTimer::getFrameCount())
{
// Ideally this should also check parcel change and landmark additions,
// not just frame change.
// But should be sufficient to check only frame as this is used
// after inventory and parcel operations.
return false;
}
sLastFrame = LLFrameTimer::getFrameCount();
LLFirstAgentParcelLandmark get_first_agent_landmark;
LLInventoryModel::cat_array_t cats;
LLInventoryModel::item_array_t items;
fetch_landmarks(cats, items, get_first_agent_landmark);
return !items.empty();
if (!items.empty())
{
sLastItemID = items[0]->getUUID();
return true;
}
return false;
}
// *TODO: This could be made more efficient by only fetching the FIRST
// landmark that meets the criteria
LLViewerInventoryItem* LLLandmarkActions::findLandmarkForGlobalPos(const LLVector3d &pos)
{
// Determine whether there are landmarks pointing to the current parcel.
// Will stop after first found landmark.
LLInventoryModel::cat_array_t cats;
LLInventoryModel::item_array_t items;
LLFetchlLandmarkByPos is_current_pos_landmark(pos);
fetch_landmarks(cats, items, is_current_pos_landmark);
LLFetchFirstLandmarkByPos get_landmark_from_pos(pos);
fetch_landmarks(cats, items, get_landmark_from_pos);
if(items.empty())
{
@@ -385,7 +460,14 @@ void LLLandmarkActions::copySLURLtoClipboard(const LLUUID& landmarkInventoryItem
{
LLVector3d global_pos;
landmark->getGlobalPos(global_pos);
LLLandmarkActions::getSLURLfromPosGlobal(global_pos,&copy_slurl_to_clipboard_callback,true);
if (!global_pos.isExactlyZero())
{
LLLandmarkActions::getSLURLfromPosGlobal(global_pos, &copy_slurl_to_clipboard_callback, true);
}
else
{
LLNotificationsUtil::add("LandmarkLocationUnknown");
}
}
}
+43 -6
View File
@@ -147,29 +147,66 @@ void LLLandmarkList::processGetAssetReply(
else
{
// failed to parse, shouldn't happen
LL_WARNS("Landmarks") << "Failed to parse landmark " << uuid << LL_ENDL;
gLandmarkList.eraseCallbacks(uuid);
}
}
else
{
// got a good status, but no file, shouldn't happen
LL_WARNS("Landmarks") << "Empty buffer for landmark " << uuid << LL_ENDL;
gLandmarkList.eraseCallbacks(uuid);
}
// We got this asset, remove it from retry and bad lists.
gLandmarkList.mRetryList.erase(uuid);
gLandmarkList.mBadList.erase(uuid);
}
else
{
// SJB: No use case for a notification here. Use LL_DEBUGS() instead
if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status )
if (LL_ERR_NO_CAP == status)
{
LL_WARNS("Landmarks") << "Missing Landmark" << LL_ENDL;
//LLNotificationsUtil::add("LandmarkMissing");
// A problem with asset cap, always allow retrying.
// Todo: should this reschedule?
gLandmarkList.mRequestedList.erase(uuid);
gLandmarkList.eraseCallbacks(uuid);
// If there was a previous request, it likely failed due to an obsolete cap
// so clear the retry marker to allow multiple retries.
gLandmarkList.mRetryList.erase(uuid);
return;
}
if (gLandmarkList.mBadList.find(uuid) != gLandmarkList.mBadList.end())
{
// Already on the 'bad' list, ignore
gLandmarkList.mRequestedList.erase(uuid);
gLandmarkList.eraseCallbacks(uuid);
return;
}
if (LL_ERR_ASSET_REQUEST_FAILED == status
&& gLandmarkList.mRetryList.find(uuid) == gLandmarkList.mRetryList.end())
{
// There is a number of reasons why an asset request can fail,
// like a cap being obsolete due to user teleporting.
// Let viewer rerequest at least once more.
// Todo: should this reshchedule?
gLandmarkList.mRetryList.emplace(uuid);
gLandmarkList.mRequestedList.erase(uuid);
gLandmarkList.eraseCallbacks(uuid);
return;
}
if (LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status)
{
LL_WARNS("Landmarks") << "Missing Landmark " << uuid << LL_ENDL;
}
else
{
LL_WARNS("Landmarks") << "Unable to load Landmark" << LL_ENDL;
//LLNotificationsUtil::add("UnableToLoadLandmark");
LL_WARNS("Landmarks") << "Unable to load Landmark " << uuid
<< ". asset status: " << status
<< ". Extended status: " << (S64)ext_status << LL_ENDL;
}
gLandmarkList.mRetryList.erase(uuid);
gLandmarkList.mBadList.insert(uuid);
gLandmarkList.mRequestedList.erase(uuid); //mBadList effectively blocks any load, so no point keeping id in requests
gLandmarkList.eraseCallbacks(uuid);
+1
View File
@@ -72,6 +72,7 @@ protected:
typedef std::set<LLUUID> landmark_uuid_list_t;
landmark_uuid_list_t mBadList;
landmark_uuid_list_t mRetryList;
typedef std::map<LLUUID,F32> landmark_requested_list_t;
landmark_requested_list_t mRequestedList;
+6 -2
View File
@@ -803,6 +803,10 @@ void LLMuteList::processMuteListUpdate(LLMessageSystem* msg, void**)
std::string unclean_filename;
msg->getStringFast(_PREHASH_MuteData, _PREHASH_Filename, unclean_filename);
std::string filename = LLDir::getScrubbedFileName(unclean_filename);
if (filename.empty())
{
LL_WARNS() << "Received empty mute list filename." << LL_ENDL;
}
LLMuteList* mute_list = getInstance();
mute_list->mLoadState = ML_REQUESTED;
@@ -835,16 +839,16 @@ void LLMuteList::processUseCachedMuteList(LLMessageSystem* msg, void**)
void LLMuteList::onFileMuteList(void** user_data, S32 error_code, LLExtStat ext_status)
{
LL_INFOS() << "LLMuteList::processMuteListFile()" << LL_ENDL;
std::string* local_filename_and_path = (std::string*)user_data;
if(local_filename_and_path && !local_filename_and_path->empty() && (error_code == 0))
{
LL_INFOS() << "Received mute list from server" << LL_ENDL;
LLMuteList::getInstance()->loadFromFile(*local_filename_and_path);
LLFile::remove(*local_filename_and_path);
}
else
{
LL_INFOS() << "LLMuteList xfer failed with code " << error_code << LL_ENDL;
LLMuteList::getInstance()->mLoadState = ML_FAILED;
}
delete local_filename_and_path;
-24
View File
@@ -559,9 +559,6 @@ void LLPanelDirBrowser::processDirEventsReply(LLMessageSystem* msg, void**)
LLUUID owner_id;
std::string name;
std::string date;
bool show_pg = gSavedSettings.getBOOL("ShowPGEvents");
bool show_mature = gSavedSettings.getBOOL("ShowMatureEvents");
bool show_adult = gSavedSettings.getBOOL("ShowAdultEvents");
msg->getUUID("AgentData", "AgentID", agent_id);
msg->getUUID("QueryData", "QueryID", query_id );
@@ -618,27 +615,6 @@ void LLPanelDirBrowser::processDirEventsReply(LLMessageSystem* msg, void**)
LL_WARNS() << "skipped event due to owner_id null, event_id " << event_id << LL_ENDL;
continue;
}
// skip events that don't match the flags
// there's no PG flag, so we make sure neither adult nor mature is set
if (((event_flags & (EVENT_FLAG_ADULT | EVENT_FLAG_MATURE)) == EVENT_FLAG_NONE) && !show_pg)
{
//llwarns << "Skipped pg event because we're not showing pg, event_id " << event_id << llendl;
continue;
}
if ((event_flags & EVENT_FLAG_MATURE) && !show_mature)
{
//llwarns << "Skipped mature event because we're not showing mature, event_id " << event_id << llendl;
continue;
}
if ((event_flags & EVENT_FLAG_ADULT) && !show_adult)
{
//llwarns << "Skipped adult event because we're not showing adult, event_id " << event_id << llendl;
continue;
}
LLSD content;
content["type"] = EVENT_CODE;
+5 -6
View File
@@ -143,18 +143,17 @@ void LLPanelDirEvents::performQueryOrDelete(U32 event_id)
static LLUICachedControl<bool> incpg("ShowPGEvents", true);
static LLUICachedControl<bool> incmature("ShowMatureEvents", false);
static LLUICachedControl<bool> incadult("ShowAdultEvents", false);
if (!(incpg || incmature || incadult))
{
LLNotificationsUtil::add("NoContentToSearch");
return;
}
U32 scope = DFQ_DATE_EVENTS;
if (incpg) scope |= DFQ_INC_PG;
if (incmature && gAgent.canAccessMature()) scope |= DFQ_INC_MATURE;
if (incadult && gAgent.canAccessAdult()) scope |= DFQ_INC_ADULT;
if ( !( scope & (DFQ_INC_PG | DFQ_INC_MATURE | DFQ_INC_ADULT )))
{
LLNotificationsUtil::add("NoContentToSearch");
return;
}
setupNewSearch();
std::ostringstream params;
-14
View File
@@ -62,20 +62,6 @@ bool LLPanelDirLand::postBuild()
childSetValue("type", gSavedSettings.getString("FindLandType"));
bool adult_enabled = gAgent.canAccessAdult();
bool mature_enabled = gAgent.canAccessMature();
childSetVisible("incpg", true);
if (!mature_enabled)
{
childSetValue("incmature", false);
childDisable("incmature");
}
if (!adult_enabled)
{
childSetValue("incadult", false);
childDisable("incadult");
}
childSetCommitCallback("pricecheck", onCommitPrice, this);
childSetCommitCallback("areacheck", onCommitArea, this);
+5 -6
View File
@@ -121,6 +121,11 @@ void LLPanelDirPlaces::performQuery()
static LLUICachedControl<bool> inc_pg("ShowPGSims", true);
static LLUICachedControl<bool> inc_mature("ShowMatureSims", false);
static LLUICachedControl<bool> inc_adult("ShowAdultSims", false);
if (!(inc_pg || inc_mature || inc_adult))
{
LLNotificationsUtil::add("NoContentToSearch");
return;
}
if (inc_pg)
{
@@ -137,12 +142,6 @@ void LLPanelDirPlaces::performQuery()
flags |= DFQ_INC_ADULT;
}
if (0x0 == flags)
{
LLNotificationsUtil::add("NoContentToSearch");
return;
}
queryCore(query_string, category, flags);
}
+23 -9
View File
@@ -1201,7 +1201,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
// See if that's been overridden by a material setting for same...
//
LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(alpha_mode, identical_alpha_mode, mIsAlpha);
LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(alpha_mode, identical_alpha_mode);
// it is invalid to have any alpha mode other than blend if transparency is greater than zero ...
// Want masking? Want emissive? Tough! You get BLEND!
@@ -1211,6 +1211,12 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
alpha_mode = mIsAlpha ? alpha_mode : LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
mComboAlphaMode->getSelectionInterface()->selectNthItem(alpha_mode);
mComboAlphaMode->setTentative(!identical_alpha_mode);
if (!identical_alpha_mode)
{
std::string multiple = LLTrans::getString("multiple_textures");
mComboAlphaMode->setLabel(multiple);
}
updateAlphaControls();
mExcludeWater &= (LLMaterial::DIFFUSE_ALPHA_MODE_BLEND == alpha_mode);
@@ -5484,32 +5490,40 @@ void LLPanelFace::LLSelectedTEMaterial::getMaxNormalRepeats(F32& repeats, bool&
identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &max_norm_repeats_func, repeats);
}
void LLPanelFace::LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical, bool diffuse_texture_has_alpha)
void LLPanelFace::LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical)
{
struct LLSelectedTEGetDiffuseAlphaMode : public LLSelectedTEGetFunctor<U8>
{
LLSelectedTEGetDiffuseAlphaMode() : _isAlpha(false) {}
LLSelectedTEGetDiffuseAlphaMode(bool diffuse_texture_has_alpha) : _isAlpha(diffuse_texture_has_alpha) {}
LLSelectedTEGetDiffuseAlphaMode() {}
virtual ~LLSelectedTEGetDiffuseAlphaMode() {}
U8 get(LLViewerObject* object, S32 face)
{
U8 diffuse_mode = _isAlpha ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
LLTextureEntry* tep = object->getTE(face);
if (tep)
{
LLMaterial* mat = tep->getMaterialParams().get();
if (mat)
{
diffuse_mode = mat->getDiffuseAlphaMode();
return mat->getDiffuseAlphaMode();
}
}
bool has_alpha = false;
LLViewerTexture* image = object->getTEImage(face);
if (image)
{
LLGLenum format = image->getPrimaryFormat();
if (format == GL_RGBA || format == GL_ALPHA)
{
has_alpha = true;
}
}
U8 diffuse_mode = has_alpha ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
return diffuse_mode;
}
bool _isAlpha; // whether or not the diffuse texture selected contains alpha information
} get_diff_mode(diffuse_texture_has_alpha);
} get_diff_mode;
identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &get_diff_mode, diffuse_alpha_mode);
}
+1 -1
View File
@@ -652,7 +652,7 @@ public:
static void getCurrent(LLMaterialPtr& material_ptr, bool& identical_material);
static void getMaxSpecularRepeats(F32& repeats, bool& identical);
static void getMaxNormalRepeats(F32& repeats, bool& identical);
static void getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical, bool diffuse_texture_has_alpha);
static void getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical);
static void selectionNormalScaleAutofit(LLPanelFace* panel_face, F32 repeats_per_meter);
static void selectionSpecularScaleAutofit(LLPanelFace* panel_face, F32 repeats_per_meter);
+61 -10
View File
@@ -42,6 +42,7 @@
#include "llcoproceduremanager.h"
#include "lleventcoro.h"
#include "llsdutil.h"
#include "llstartup.h"
#include "llworld.h"
///----------------------------------------------------------------------------
@@ -460,28 +461,78 @@ void LLViewerAssetStorage::assetRequestCoro(
if (!gAgent.getRegion())
{
LL_WARNS_ONCE("ViewerAsset") << "Asset request fails: no region set" << LL_ENDL;
result_code = LL_ERR_ASSET_REQUEST_FAILED;
ext_status = LLExtStat::NONE;
removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status, 0);
return;
if (STATE_WORLD_INIT <= LLStartUp::getStartupState())
{
// Viewer isn't ready, wait for region to become available
LL_INFOS_ONCE("ViewerAsset") << "Waiting for agent region to be set" << LL_ENDL;
LLEventStream region_init("waitForRegion", true);
std::string pump_name = region_init.getName();
boost::signals2::connection region_conn =
gAgent.addRegionChangedCallback([pump_name]()
{
LLEventPumps::instance().obtain(pump_name).post(LLSD());
});
F32Seconds timeout_seconds(LL_ASSET_STORAGE_TIMEOUT);
llcoro::suspendUntilEventOnWithTimeout(region_init, timeout_seconds, LLSDMap("timeout", LLSD::Boolean(true)));
gAgent.removeRegionChangedCallback(region_conn);
region_conn.disconnect();
if (LLApp::isExiting() || !gAssetStorage)
{
return;
}
// recheck region whether suspend ended on timeout or not
if (!gAgent.getRegion())
{
LL_WARNS_ONCE("ViewerAsset") << "Asset request fails: timeout reached while waiting for region" << LL_ENDL;
result_code = LL_ERR_NO_CAP;
ext_status = LLExtStat::NONE;
removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status, 0);
return;
}
}
else
{
LL_WARNS_ONCE("ViewerAsset") << "Asset request fails: no region set" << LL_ENDL;
result_code = LL_ERR_NO_CAP;
ext_status = LLExtStat::NONE;
removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status, 0);
return;
}
}
else if (!gAgent.getRegion()->capabilitiesReceived())
if (!gAgent.getRegion()->capabilitiesReceived())
{
LL_WARNS_ONCE("ViewerAsset") << "Waiting for capabilities" << LL_ENDL;
LLEventStream capsRecv("waitForCaps", true);
gAgent.getRegion()->setCapabilitiesReceivedCallback(
boost::bind(&LLViewerAssetStorage::capsRecvForRegion, this, _1, capsRecv.getName()));
boost::signals2::connection caps_conn =
gAgent.getRegion()->setCapabilitiesReceivedCallback(
boost::bind(&LLViewerAssetStorage::capsRecvForRegion, this, _1, capsRecv.getName()));
llcoro::suspendUntilEventOn(capsRecv);
F32Seconds timeout_seconds(LL_ASSET_STORAGE_TIMEOUT); // from minutes to seconds, by default 5 minutes
LLSD result = llcoro::suspendUntilEventOnWithTimeout(capsRecv, timeout_seconds, LLSDMap("timeout", LLSD::Boolean(true)));
caps_conn.disconnect();
if (LLApp::isExiting() || !gAssetStorage)
{
return;
}
if (result.has("timeout"))
{
// Caps failed to arrive in 5 minutes
LL_WARNS_ONCE("ViewerAsset") << "Asset " << uuid << " request fails : capabilities took too long to arrive" << LL_ENDL;
result_code = LL_ERR_NO_CAP;
ext_status = LLExtStat::NONE;
removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status, 0);
return;
}
LL_WARNS_ONCE("ViewerAsset") << "capsRecv got event" << LL_ENDL;
LL_WARNS_ONCE("ViewerAsset") << "region " << gAgent.getRegion() << " mViewerAssetUrl " << mViewerAssetUrl << LL_ENDL;
}
@@ -492,7 +543,7 @@ void LLViewerAssetStorage::assetRequestCoro(
if (mViewerAssetUrl.empty())
{
LL_WARNS_ONCE("ViewerAsset") << "asset request fails: caps received but no viewer asset cap found" << LL_ENDL;
result_code = LL_ERR_ASSET_REQUEST_FAILED;
result_code = LL_ERR_NO_CAP;
ext_status = LLExtStat::NONE;
removeAndCallbackPendingDownloads(uuid, atype, uuid, atype, result_code, ext_status, 0);
return;
+8 -5
View File
@@ -6666,11 +6666,8 @@ class LLAvatarEnableResetSkeleton : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
if (LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()))
{
return true;
}
return false;
LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
return obj && obj->getAvatar();
}
};
@@ -8715,6 +8712,12 @@ LLVOAvatar* find_avatar_from_object(LLViewerObject* object)
}
else if( !object->isAvatar() )
{
// Check for animesh objects (animated objects with a control avatar)
LLVOAvatar* avatar = object->getAvatar();
if (avatar)
{
return avatar;
}
object = NULL;
}
}
+8 -6
View File
@@ -2549,10 +2549,7 @@ void LLVoiceWebRTCConnection::OnRenegotiationNeeded()
LL::WorkQueue::postMaybe(mMainQueue,
[=, this] {
LL_DEBUGS("Voice") << "Voice channel requires renegotiation." << LL_ENDL;
if (!mShutDown)
{
setVoiceConnectionState(VOICE_STATE_SESSION_RETRY);
}
setVoiceConnectionState(VOICE_STATE_SESSION_RETRY);
mCurrentStatus = LLVoiceClientStatusObserver::ERROR_UNKNOWN;
});
}
@@ -2898,9 +2895,10 @@ bool LLVoiceWebRTCConnection::connectionStateMachine()
// this connection.
// For spatial this connection will come up as muted, but will be set to the appropriate
// value later on when we determine the regions we connect to.
if (!isSpatial())
if (isSpatial())
{
mWebRTCAudioInterface->setMute(mMuted);
// we'll determine primary state later and set mute accordinly
mPrimary = false;
}
mWebRTCAudioInterface->setReceiveVolume(mSpeakerVolume);
LLWebRTCVoiceClient::getInstance()->OnConnectionEstablished(mChannelID, mRegionID);
@@ -2924,6 +2922,10 @@ bool LLVoiceWebRTCConnection::connectionStateMachine()
LLWebRTCVoiceClient::getInstance()->updatePosition();
LLWebRTCVoiceClient::getInstance()->sendPositionUpdate(true);
}
else
{
mWebRTCAudioInterface->setMute(mMuted);
}
}
break;
}
@@ -2483,7 +2483,7 @@ You already have a landmark for this location.
icon="alert.tga"
name="LandmarkLocationUnknown"
type="alert">
Viewer wasn't able to get region's location. Region might be temporarily unavailable or was removed.
Viewer wasn't able to get region's location. Region might be temporarily unavailable, was removed or landmark failed to load.
<usetemplate
name="okbutton"
yestext="OK"/>
+3 -2
View File
@@ -259,9 +259,10 @@ class ViewerManifest(LLManifest):
global CHANNEL_VENDOR_BASE
channel_type=self.channel_type()
if channel_type == 'release':
return CHANNEL_VENDOR_BASE
app_suffix='Viewer'
else:
return CHANNEL_VENDOR_BASE + ' ' + self.channel_variant()
app_suffix=self.channel_variant()
return CHANNEL_VENDOR_BASE + ' ' + app_suffix
def exec_name(self):
return "SecondLifeViewer"