Merge branch 'develop' of https://github.com/secondlife/viewer
# Conflicts: # indra/llui/lltextbase.cpp # indra/newview/llappviewerwin32.cpp # indra/newview/lleventpoll.cppmaster
commit
5e5a3f4102
|
|
@ -97,7 +97,7 @@ jobs:
|
|||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: secondlife/build-variables
|
||||
ref: universal
|
||||
ref: master
|
||||
path: .build-variables
|
||||
|
||||
- name: Checkout master-message-template
|
||||
|
|
@ -309,7 +309,7 @@ jobs:
|
|||
steps:
|
||||
- name: Sign and package Windows viewer
|
||||
if: env.AZURE_KEY_VAULT_URI && env.AZURE_CERT_NAME && env.AZURE_CLIENT_ID && env.AZURE_CLIENT_SECRET && env.AZURE_TENANT_ID
|
||||
uses: secondlife/viewer-build-util/sign-pkg-windows@v2
|
||||
uses: secondlife/viewer-build-util/sign-pkg-windows@v2.0.4
|
||||
with:
|
||||
vault_uri: "${{ env.AZURE_KEY_VAULT_URI }}"
|
||||
cert_name: "${{ env.AZURE_CERT_NAME }}"
|
||||
|
|
|
|||
|
|
@ -188,6 +188,17 @@ public:
|
|||
<< childout.peek(0, peeklen) << "..." << LL_ENDL;
|
||||
}
|
||||
|
||||
// Handle any remaining stderr data (partial lines) the same way as we do
|
||||
// for stdout: log it.
|
||||
LLProcess::ReadPipe& childerr(mChild->getReadPipe(LLProcess::STDERR));
|
||||
if (childerr.size())
|
||||
{
|
||||
LLProcess::ReadPipe::size_type
|
||||
peeklen((std::min)(LLProcess::ReadPipe::size_type(50), childerr.size()));
|
||||
LL_WARNS("LLLeap") << "Final stderr " << childerr.size() << " bytes: "
|
||||
<< childerr.peek(0, peeklen) << "..." << LL_ENDL;
|
||||
}
|
||||
|
||||
// Kill this instance. MUST BE LAST before return!
|
||||
delete this;
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -557,11 +557,6 @@ public:
|
|||
|
||||
}
|
||||
|
||||
if (!opj_setup_encoder(encoder, ¶meters, image))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
U32 width_tiles = (rawImageIn.getWidth() >> 6);
|
||||
U32 height_tiles = (rawImageIn.getHeight() >> 6);
|
||||
|
||||
|
|
@ -575,6 +570,19 @@ public:
|
|||
height_tiles = 1;
|
||||
}
|
||||
|
||||
if (width_tiles == 1 || height_tiles == 1)
|
||||
{
|
||||
// Images with either dimension less than 32 need less number of resolutions otherwise they error
|
||||
int min_dim = rawImageIn.getWidth() < rawImageIn.getHeight() ? rawImageIn.getWidth() : rawImageIn.getHeight();
|
||||
int max_res = 1 + (int)floor(log2(min_dim));
|
||||
parameters.numresolution = max_res;
|
||||
}
|
||||
|
||||
if (!opj_setup_encoder(encoder, ¶meters, image))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
U32 tile_count = width_tiles * height_tiles;
|
||||
U32 data_size_guess = tile_count * TILE_SIZE;
|
||||
|
||||
|
|
|
|||
|
|
@ -1604,6 +1604,7 @@ bool LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask )
|
|||
&& ( count > 0 && (hasVisibleChildren()) ))) && // show menu only if selected items are visible
|
||||
!hide_folder_menu)
|
||||
{
|
||||
LL_INFOS("Inventory") << "Opening inventory menu from path: " << getPathname() << LL_ENDL;
|
||||
if (mCallbackRegistrar)
|
||||
{
|
||||
mCallbackRegistrar->pushScope();
|
||||
|
|
|
|||
|
|
@ -207,6 +207,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
|
|||
mURLClickSignal(NULL),
|
||||
mIsFriendSignal(NULL),
|
||||
mIsObjectBlockedSignal(NULL),
|
||||
mIsObjectReachableSignal(NULL),
|
||||
mMaxTextByteLength( p.max_text_length ),
|
||||
mFont(p.font),
|
||||
mFontShadow(p.font_shadow),
|
||||
|
|
@ -320,6 +321,7 @@ LLTextBase::~LLTextBase()
|
|||
delete mURLClickSignal;
|
||||
delete mIsFriendSignal;
|
||||
delete mIsObjectBlockedSignal;
|
||||
delete mIsObjectReachableSignal;
|
||||
}
|
||||
|
||||
void LLTextBase::initFromParams(const LLTextBase::Params& p)
|
||||
|
|
@ -2510,6 +2512,15 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url)
|
|||
}
|
||||
}
|
||||
|
||||
if (mIsObjectReachableSignal)
|
||||
{
|
||||
bool is_reachable = *(*mIsObjectReachableSignal)(LLUUID(LLUrlAction::getObjectId(url)));
|
||||
if (LLView* zoom_btn = menu->getChild<LLView>("zoom_in"))
|
||||
{
|
||||
zoom_btn->setEnabled(is_reachable);
|
||||
}
|
||||
}
|
||||
|
||||
// <FS:Zi> hide the moderation tools in the context menu unless we are in a group IM floater
|
||||
LLFloater* parent_floater = getParentByType<LLFloater>();
|
||||
if (!parent_floater || parent_floater->getName() != "panel_im")
|
||||
|
|
@ -3740,6 +3751,15 @@ boost::signals2::connection LLTextBase::setIsObjectBlockedCallback(const is_bloc
|
|||
return mIsObjectBlockedSignal->connect(cb);
|
||||
}
|
||||
|
||||
boost::signals2::connection LLTextBase::setIsObjectReachableCallback(const is_obj_reachable_signal_t::slot_type& cb)
|
||||
{
|
||||
if (!mIsObjectReachableSignal)
|
||||
{
|
||||
mIsObjectReachableSignal = new is_obj_reachable_signal_t();
|
||||
}
|
||||
return mIsObjectReachableSignal->connect(cb);
|
||||
}
|
||||
|
||||
//
|
||||
// LLTextSegment
|
||||
//
|
||||
|
|
|
|||
|
|
@ -346,6 +346,7 @@ public:
|
|||
|
||||
typedef boost::signals2::signal<bool (const LLUUID& user_id)> is_friend_signal_t;
|
||||
typedef boost::signals2::signal<bool (const LLUUID& blocked_id, const std::string from)> is_blocked_signal_t;
|
||||
typedef boost::signals2::signal<bool (const LLUUID& obj_id)> is_obj_reachable_signal_t;
|
||||
|
||||
struct LineSpacingParams : public LLInitParam::ChoiceBlock<LineSpacingParams>
|
||||
{
|
||||
|
|
@ -572,6 +573,7 @@ public:
|
|||
boost::signals2::connection setURLClickedCallback(const commit_signal_t::slot_type& cb);
|
||||
boost::signals2::connection setIsFriendCallback(const is_friend_signal_t::slot_type& cb);
|
||||
boost::signals2::connection setIsObjectBlockedCallback(const is_blocked_signal_t::slot_type& cb);
|
||||
boost::signals2::connection setIsObjectReachableCallback(const is_obj_reachable_signal_t::slot_type& cb);
|
||||
|
||||
void setWordWrap(bool wrap);
|
||||
LLScrollContainer* getScrollContainer() const { return mScroller; }
|
||||
|
|
@ -841,6 +843,7 @@ protected:
|
|||
// Used to check if user with given ID is avatar's friend
|
||||
is_friend_signal_t* mIsFriendSignal;
|
||||
is_blocked_signal_t* mIsObjectBlockedSignal;
|
||||
is_obj_reachable_signal_t* mIsObjectReachableSignal;
|
||||
|
||||
LLUIString mLabel; // text label that is visible when no user text provided
|
||||
// <FS:Ansariel> Optional icon position
|
||||
|
|
|
|||
|
|
@ -350,6 +350,16 @@ void LLWebRTCImpl::init()
|
|||
|
||||
void LLWebRTCImpl::terminate()
|
||||
{
|
||||
mWorkerThread->BlockingCall(
|
||||
[this]()
|
||||
{
|
||||
if (mDeviceModule)
|
||||
{
|
||||
mDeviceModule->ForceStopRecording();
|
||||
mDeviceModule->StopPlayout();
|
||||
}
|
||||
});
|
||||
|
||||
for (auto &connection : mPeerConnections)
|
||||
{
|
||||
connection->terminate();
|
||||
|
|
@ -368,8 +378,6 @@ void LLWebRTCImpl::terminate()
|
|||
{
|
||||
if (mDeviceModule)
|
||||
{
|
||||
mDeviceModule->StopRecording();
|
||||
mDeviceModule->StopPlayout();
|
||||
mDeviceModule->Terminate();
|
||||
}
|
||||
mDeviceModule = nullptr;
|
||||
|
|
@ -442,11 +450,7 @@ void LLWebRTCImpl::unsetDevicesObserver(LLWebRTCDevicesObserver *observer)
|
|||
void LLWebRTCImpl::workerDeployDevices()
|
||||
{
|
||||
int16_t recordingDevice = RECORD_DEVICE_DEFAULT;
|
||||
#if WEBRTC_WIN
|
||||
int16_t recording_device_start = 0;
|
||||
#else
|
||||
int16_t recording_device_start = 1;
|
||||
#endif
|
||||
|
||||
if (mRecordingDevice != "Default")
|
||||
{
|
||||
|
|
@ -455,6 +459,12 @@ void LLWebRTCImpl::workerDeployDevices()
|
|||
if (mRecordingDeviceList[i].mID == mRecordingDevice)
|
||||
{
|
||||
recordingDevice = i;
|
||||
#if !WEBRTC_WIN
|
||||
// linux and mac devices range from 1 to the end of the list, with the index 0 being the
|
||||
// 'default' device. Windows has a special 'default' device and other devices are indexed
|
||||
// from 0
|
||||
recordingDevice++;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -479,11 +489,7 @@ void LLWebRTCImpl::workerDeployDevices()
|
|||
mDeviceModule->InitRecording();
|
||||
|
||||
int16_t playoutDevice = PLAYOUT_DEVICE_DEFAULT;
|
||||
#if WEBRTC_WIN
|
||||
int16_t playout_device_start = 0;
|
||||
#else
|
||||
int16_t playout_device_start = 1;
|
||||
#endif
|
||||
if (mPlayoutDevice != "Default")
|
||||
{
|
||||
for (int16_t i = playout_device_start; i < mPlayoutDeviceList.size(); i++)
|
||||
|
|
@ -491,6 +497,12 @@ void LLWebRTCImpl::workerDeployDevices()
|
|||
if (mPlayoutDeviceList[i].mID == mPlayoutDevice)
|
||||
{
|
||||
playoutDevice = i;
|
||||
#if !WEBRTC_WIN
|
||||
// linux and mac devices range from 1 to the end of the list, with the index 0 being the
|
||||
// 'default' device. Windows has a special 'default' device and other devices are indexed
|
||||
// from 0
|
||||
playoutDevice++;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -546,20 +558,14 @@ void LLWebRTCImpl::workerDeployDevices()
|
|||
void LLWebRTCImpl::setCaptureDevice(const std::string &id)
|
||||
{
|
||||
|
||||
if (mRecordingDevice != id)
|
||||
{
|
||||
mRecordingDevice = id;
|
||||
deployDevices();
|
||||
}
|
||||
mRecordingDevice = id;
|
||||
deployDevices();
|
||||
}
|
||||
|
||||
void LLWebRTCImpl::setRenderDevice(const std::string &id)
|
||||
{
|
||||
if (mPlayoutDevice != id)
|
||||
{
|
||||
mPlayoutDevice = id;
|
||||
deployDevices();
|
||||
}
|
||||
mPlayoutDevice = id;
|
||||
deployDevices();
|
||||
}
|
||||
|
||||
// updateDevices needs to happen on the worker thread.
|
||||
|
|
@ -609,7 +615,7 @@ void LLWebRTCImpl::updateDevices()
|
|||
|
||||
void LLWebRTCImpl::OnDevicesUpdated()
|
||||
{
|
||||
deployDevices();
|
||||
updateDevices();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -239,8 +239,10 @@ public:
|
|||
return 0;
|
||||
}
|
||||
int32_t StopRecording() override {
|
||||
if (tuning_) return 0; // if we're tuning, disregard the StopRecording we get from disabling the streams
|
||||
return inner_->StopRecording();
|
||||
// ignore stop recording as webrtc.lib will send one when streams shut down,
|
||||
// even if there are other streams in place. Start/Stop recording are entirely
|
||||
// controlled by the app
|
||||
return 0;
|
||||
}
|
||||
int32_t ForceStartRecording() { return inner_->StartRecording(); }
|
||||
int32_t ForceStopRecording() { return inner_->StopRecording(); }
|
||||
|
|
|
|||
|
|
@ -68,7 +68,13 @@ void LLWindowCallbacks::handleMouseLeave(LLWindow *window)
|
|||
return;
|
||||
}
|
||||
|
||||
bool LLWindowCallbacks::handleCloseRequest(LLWindow *window)
|
||||
bool LLWindowCallbacks::handleCloseRequest(LLWindow *window, bool from_user)
|
||||
{
|
||||
//allow the window to close
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLWindowCallbacks::handleSessionExit(LLWindow* window)
|
||||
{
|
||||
//allow the window to close
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@ public:
|
|||
virtual bool handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask);
|
||||
virtual void handleMouseLeave(LLWindow *window);
|
||||
// return true to allow window to close, which will then cause handleQuit to be called
|
||||
virtual bool handleCloseRequest(LLWindow *window);
|
||||
virtual bool handleCloseRequest(LLWindow *window, bool from_user);
|
||||
virtual bool handleSessionExit(LLWindow* window);
|
||||
// window is about to be destroyed, clean up your business
|
||||
virtual void handleQuit(LLWindow *window);
|
||||
virtual bool handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK mask);
|
||||
|
|
|
|||
|
|
@ -618,7 +618,7 @@ void callQuitHandler()
|
|||
{
|
||||
if (gWindowImplementation && gWindowImplementation->getCallbacks())
|
||||
{
|
||||
if(gWindowImplementation->getCallbacks()->handleCloseRequest(gWindowImplementation))
|
||||
if(gWindowImplementation->getCallbacks()->handleCloseRequest(gWindowImplementation, true))
|
||||
{
|
||||
gWindowImplementation->getCallbacks()->handleQuit(gWindowImplementation);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2170,7 +2170,7 @@ void LLWindowSDL::gatherInput()
|
|||
{
|
||||
// *FIX: More informative dialog?
|
||||
LL_INFOS() << "Could not recreate context after resize! Quitting..." << LL_ENDL;
|
||||
if(mCallbacks->handleCloseRequest(this))
|
||||
if(mCallbacks->handleCloseRequest(this, false))
|
||||
{
|
||||
// Get the app to initiate cleanup.
|
||||
mCallbacks->handleQuit(this);
|
||||
|
|
@ -2220,7 +2220,7 @@ void LLWindowSDL::gatherInput()
|
|||
break;
|
||||
|
||||
case SDL_QUIT:
|
||||
if(mCallbacks->handleCloseRequest(this))
|
||||
if(mCallbacks->handleCloseRequest(this, true))
|
||||
{
|
||||
// Get the app to initiate cleanup.
|
||||
mCallbacks->handleQuit(this);
|
||||
|
|
|
|||
|
|
@ -2556,10 +2556,13 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
|||
case WM_CLOSE:
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_CLOSE");
|
||||
// todo: WM_CLOSE can be caused by user and by task manager,
|
||||
// distinguish these cases.
|
||||
// For now assume it is always user.
|
||||
window_imp->post([=]()
|
||||
{
|
||||
// Will the app allow the window to close?
|
||||
if (window_imp->mCallbacks->handleCloseRequest(window_imp))
|
||||
if (window_imp->mCallbacks->handleCloseRequest(window_imp, true))
|
||||
{
|
||||
// Get the app to initiate cleanup.
|
||||
window_imp->mCallbacks->handleQuit(window_imp);
|
||||
|
|
@ -2577,6 +2580,50 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
case WM_QUERYENDSESSION:
|
||||
{
|
||||
// Generally means that OS is going to shut down or user is going to log off.
|
||||
// Can use ShutdownBlockReasonCreate here.
|
||||
LL_INFOS("Window") << "Received WM_QUERYENDSESSION with wParam: " << (U32)w_param << " lParam: " << (U32)l_param << LL_ENDL;
|
||||
return TRUE; // 1 = ok to end session. 0 no longer works by itself, use ShutdownBlockReasonCreate
|
||||
}
|
||||
case WM_ENDSESSION:
|
||||
{
|
||||
// OS session is shutting down, initiate cleanup.
|
||||
// Comes after WM_QUERYENDSESSION
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_ENDSESSION");
|
||||
LL_INFOS("Window") << "Received WM_ENDSESSION with wParam: " << (U32)w_param << " lParam: " << (U32)l_param << LL_ENDL;
|
||||
unsigned int end_session_flags = (U32)w_param;
|
||||
if (end_session_flags == 0)
|
||||
{
|
||||
// session is not actually ending
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((end_session_flags & ENDSESSION_CLOSEAPP)
|
||||
|| (end_session_flags & ENDSESSION_CRITICAL)
|
||||
|| (end_session_flags & ENDSESSION_LOGOFF))
|
||||
{
|
||||
window_imp->post([=]()
|
||||
{
|
||||
// Check if app needs cleanup or can be closed immediately.
|
||||
if (window_imp->mCallbacks->handleSessionExit(window_imp))
|
||||
{
|
||||
// Get the app to initiate cleanup.
|
||||
window_imp->mCallbacks->handleQuit(window_imp);
|
||||
// The app is responsible for calling destroyWindow when done with GL
|
||||
}
|
||||
});
|
||||
// Give app a second to finish up. That's not enough for a clean exit,
|
||||
// but better than nothing.
|
||||
// Todo: sync this better, some kind of waitForResult? Can't wait forever,
|
||||
// but can potentially use ShutdownBlockReasonCreate for a bigger delay.
|
||||
ms_sleep(1000);
|
||||
}
|
||||
// Don't need to post quit or destroy window,
|
||||
// if session is ending OS is going to take care of it.
|
||||
return 0;
|
||||
}
|
||||
case WM_COMMAND:
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_COMMAND");
|
||||
|
|
|
|||
|
|
@ -12680,7 +12680,7 @@ Change of this parameter will affect the layout of buttons in notification toast
|
|||
<key>RenderQualityPerformance</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Which graphics settings you've chosen</string>
|
||||
<string>Which graphics settings you've chosen. Don't use this setting to change quality directly from debug settings.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
|
|
@ -12688,7 +12688,18 @@ Change of this parameter will affect the layout of buttons in notification toast
|
|||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
|
||||
<key>DebugQualityPerformance</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Allows to change performance quality directly from debug settings.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>U32</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
|
||||
<key>RenderReflectionDetail</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
|
|||
|
|
@ -238,7 +238,8 @@ public:
|
|||
LLUUID obj_id = mObjectData["object_id"];
|
||||
if (obj_id.notNull())
|
||||
{
|
||||
return nullptr != gObjectList.findObject(mAvatarID);
|
||||
LLViewerObject* object = gObjectList.findObject(obj_id);
|
||||
return object && object->isReachable();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1280,6 +1281,11 @@ FSChatHistory::FSChatHistory(const FSChatHistory::Params& p)
|
|||
mUseColor = true;
|
||||
|
||||
setIsObjectBlockedCallback(boost::bind(&LLMuteList::isMuted, LLMuteList::getInstance(), _1, _2, 0));
|
||||
setIsObjectReachableCallback([](const LLUUID& obj_id)
|
||||
{
|
||||
LLViewerObject* object = gObjectList.findObject(obj_id);
|
||||
return object && object->isReachable();
|
||||
});
|
||||
}
|
||||
|
||||
LLSD FSChatHistory::getValue() const
|
||||
|
|
|
|||
|
|
@ -158,6 +158,11 @@ bool Buffer::prep(Asset& asset)
|
|||
{
|
||||
std::string dir = gDirUtilp->getDirName(asset.mFilename);
|
||||
std::string bin_file = dir + gDirUtilp->getDirDelimiter() + mUri;
|
||||
if (!gDirUtilp->fileExists(bin_file))
|
||||
{
|
||||
// Characters might be escaped in the URI
|
||||
bin_file = dir + gDirUtilp->getDirDelimiter() + LLURI::unescape(mUri);
|
||||
}
|
||||
|
||||
llifstream file(bin_file.c_str(), std::ios::binary);
|
||||
if (!file.is_open())
|
||||
|
|
|
|||
|
|
@ -652,6 +652,14 @@ std::string LLGLTFLoader::processTexture(S32 texture_index, const std::string& t
|
|||
filename = filename.substr(pos + 1);
|
||||
}
|
||||
|
||||
std::string dir = gDirUtilp->getDirName(mFilename);
|
||||
std::string full_path = dir + gDirUtilp->getDirDelimiter() + filename;
|
||||
if (!gDirUtilp->fileExists(full_path) && filename.find("data:") == std::string::npos)
|
||||
{
|
||||
// Uri might be escaped
|
||||
filename = LLURI::unescape(filename);
|
||||
}
|
||||
|
||||
LL_INFOS("GLTF_IMPORT") << "Found texture: " << filename << " for material: " << material_name << LL_ENDL;
|
||||
|
||||
LLSD args;
|
||||
|
|
|
|||
|
|
@ -1427,19 +1427,10 @@ bool LLAppViewer::init()
|
|||
LLStringOps::setupMonthShortNames(LLTrans::getString("dateTimeMonthShortNames"));
|
||||
LLStringOps::setupDayFormat(LLTrans::getString("dateTimeDayFormat"));
|
||||
|
||||
// <FS:Ansariel> Always override AM/PM because otherwise AM/PM indicator might be empty strings when calling using
|
||||
// [ampm,datetime,...] formatting depending on locale
|
||||
// LLStringOps::sAM = LLTrans::getString("dateTimeAM");
|
||||
// LLStringOps::sPM = LLTrans::getString("dateTimePM");
|
||||
// </FS:Ansariel>
|
||||
LLStringOps::sAM = LLTrans::getString("dateTimeAM");
|
||||
LLStringOps::sPM = LLTrans::getString("dateTimePM");
|
||||
}
|
||||
|
||||
// <FS:Ansariel> Always override AM/PM because otherwise AM/PM indicator might be empty strings when calling using [ampm,datetime,...]
|
||||
// formatting depending on locale
|
||||
LLStringOps::sAM = LLTrans::getString("dateTimeAM");
|
||||
LLStringOps::sPM = LLTrans::getString("dateTimePM");
|
||||
// </FS:Ansariel>
|
||||
|
||||
LLAgentLanguage::init();
|
||||
|
||||
/// Tell the Coprocedure manager how to discover and store the pool sizes
|
||||
|
|
@ -1487,6 +1478,7 @@ bool LLAppViewer::init()
|
|||
LLViewerCamera::createInstance();
|
||||
LL::GLTFSceneManager::createInstance();
|
||||
|
||||
gSavedSettings.setU32("DebugQualityPerformance", gSavedSettings.getU32("RenderQualityPerformance"));
|
||||
|
||||
#if LL_WINDOWS
|
||||
if (!mSecondInstance)
|
||||
|
|
@ -4738,8 +4730,15 @@ void LLAppViewer::processMarkerFiles()
|
|||
else if (marker_is_same_version)
|
||||
{
|
||||
// the file existed, is ours, and matched our version, so we can report on what it says
|
||||
LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found; last exec crashed" << LL_ENDL;
|
||||
LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found; last exec crashed or froze" << LL_ENDL;
|
||||
#if LL_WINDOWS && LL_BUGSPLAT
|
||||
// bugsplat will set correct state in bugsplatSendLog
|
||||
// Might be more accurate to rename this one into 'unknown'
|
||||
gLastExecEvent = LAST_EXEC_FROZE;
|
||||
#else
|
||||
gLastExecEvent = LAST_EXEC_OTHER_CRASH;
|
||||
#endif // LL_WINDOWS
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -4999,7 +4998,7 @@ void LLAppViewer::earlyExit(const std::string& name, const LLSD& substitutions)
|
|||
// case where we need the viewer to exit without any need for notifications
|
||||
void LLAppViewer::earlyExitNoNotify()
|
||||
{
|
||||
LL_WARNS() << "app_early_exit with no notification: " << LL_ENDL;
|
||||
LL_WARNS() << "app_early_exit with no notification." << LL_ENDL;
|
||||
gDoDisconnect = true;
|
||||
finish_early_exit( LLSD(), LLSD() );
|
||||
}
|
||||
|
|
@ -6330,6 +6329,12 @@ void LLAppViewer::createErrorMarker(eLastExecEvent error_code) const
|
|||
}
|
||||
}
|
||||
|
||||
bool LLAppViewer::errorMarkerExists() const
|
||||
{
|
||||
std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME);
|
||||
return LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB);
|
||||
}
|
||||
|
||||
void LLAppViewer::outOfMemorySoftQuit()
|
||||
{
|
||||
if (!mQuitRequested)
|
||||
|
|
|
|||
|
|
@ -149,6 +149,12 @@ public:
|
|||
std::string getWindowTitle() const; // The window display name.
|
||||
|
||||
void forceDisconnect(const std::string& msg); // Force disconnection, with a message to the user.
|
||||
|
||||
// sendSimpleLogoutRequest does not create a marker file.
|
||||
// Meant for lost network case, and for forced shutdowns,
|
||||
// to at least attempt to remove the ghost from the world.
|
||||
void sendSimpleLogoutRequest();
|
||||
|
||||
void badNetworkHandler(); // Cause a crash state due to bad network packet.
|
||||
|
||||
bool hasSavedFinalSnapshot() { return mSavedFinalSnapshot; }
|
||||
|
|
@ -246,6 +252,7 @@ public:
|
|||
|
||||
// Writes an error code into the error_marker file for use on next startup.
|
||||
void createErrorMarker(eLastExecEvent error_code) const;
|
||||
bool errorMarkerExists() const;
|
||||
|
||||
// Attempt a 'soft' quit with disconnect and saving of settings/cache.
|
||||
// Intended to be thread safe.
|
||||
|
|
@ -314,10 +321,6 @@ private:
|
|||
void sendLogoutRequest();
|
||||
void disconnectViewer();
|
||||
|
||||
// Does not create a marker file. For lost network case,
|
||||
// to at least attempt to remove the ghost from the world.
|
||||
void sendSimpleLogoutRequest();
|
||||
|
||||
// *FIX: the app viewer class should be some sort of singleton, no?
|
||||
// Perhaps its child class is the singleton and this should be an abstract base.
|
||||
static LLAppViewer* sInstance;
|
||||
|
|
|
|||
|
|
@ -233,10 +233,20 @@ namespace
|
|||
BugSplatAttributes::instance().setAttribute("Location", std::string(fullLocation));
|
||||
// </FS:Beq>
|
||||
}
|
||||
|
||||
// <FS:Beq> Improve bugsplat reporting with attributes
|
||||
LLAppViewer::instance()->writeDebugInfo();
|
||||
sBugSplatSender->sendAdditionalFile(WCSTR(BugSplatAttributes::getCrashContextFileName())); // <FS:Beq/> Add the new attributes file
|
||||
// </FS:Beq>
|
||||
|
||||
LLAppViewer* app = LLAppViewer::instance();
|
||||
if (!app->isSecondInstance() && !app->errorMarkerExists())
|
||||
{
|
||||
// If marker doesn't exist, create a marker with 'other' code for next launch
|
||||
// otherwise don't override existing file
|
||||
// Any unmarked crashes will be considered as freezes
|
||||
app->createErrorMarker(LAST_EXEC_OTHER_CRASH);
|
||||
}
|
||||
} // MDSCB_EXCEPTIONCODE
|
||||
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -229,7 +229,8 @@ public:
|
|||
LLUUID obj_id = mObjectData["object_id"];
|
||||
if (obj_id.notNull())
|
||||
{
|
||||
return nullptr != gObjectList.findObject(mAvatarID);
|
||||
LLViewerObject* object = gObjectList.findObject(obj_id);
|
||||
return object && object->isReachable();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1178,7 +1179,11 @@ LLChatHistory::LLChatHistory(const LLChatHistory::Params& p)
|
|||
mEditor = LLUICtrlFactory::create<LLTextEditor>(editor_params, this);
|
||||
mEditor->setIsFriendCallback(LLAvatarActions::isFriend);
|
||||
mEditor->setIsObjectBlockedCallback(boost::bind(&LLMuteList::isMuted, LLMuteList::getInstance(), _1, _2, 0));
|
||||
|
||||
mEditor->setIsObjectReachableCallback([](const LLUUID& obj_id)
|
||||
{
|
||||
LLViewerObject* object = gObjectList.findObject(obj_id);
|
||||
return object && object->isReachable();
|
||||
});
|
||||
}
|
||||
|
||||
LLSD LLChatHistory::getValue() const
|
||||
|
|
|
|||
|
|
@ -57,13 +57,6 @@ namespace Details
|
|||
void stop();
|
||||
|
||||
private:
|
||||
// We will wait RETRY_SECONDS + (errorCount * RETRY_SECONDS_INC) before retrying after an error.
|
||||
// This means we attempt to recover relatively quickly but back off giving more time to recover
|
||||
// until we finally give up after MAX_EVENT_POLL_HTTP_ERRORS attempts.
|
||||
static const F32 EVENT_POLL_ERROR_RETRY_SECONDS;
|
||||
static const F32 EVENT_POLL_ERROR_RETRY_SECONDS_INC;
|
||||
static const S32 MAX_EVENT_POLL_HTTP_ERRORS;
|
||||
|
||||
void eventPollCoro(std::string url);
|
||||
|
||||
void handleMessage(const LLSD &content);
|
||||
|
|
@ -71,7 +64,6 @@ namespace Details
|
|||
bool mDone;
|
||||
LLCore::HttpRequest::ptr_t mHttpRequest;
|
||||
LLCore::HttpRequest::policy_t mHttpPolicy;
|
||||
LLCore::HttpOptions::ptr_t mHttpOptions; // <FS:Ansariel> Restore pre-coro behavior (60s timeout, no retries)
|
||||
std::string mSenderIp;
|
||||
int mCounter;
|
||||
LLCoreHttpUtil::HttpCoroutineAdapter::wptr_t mAdapter;
|
||||
|
|
@ -80,9 +72,13 @@ namespace Details
|
|||
};
|
||||
|
||||
|
||||
const F32 LLEventPollImpl::EVENT_POLL_ERROR_RETRY_SECONDS = 15.f; // ~ half of a normal timeout.
|
||||
const F32 LLEventPollImpl::EVENT_POLL_ERROR_RETRY_SECONDS_INC = 5.f; // ~ half of a normal timeout.
|
||||
const S32 LLEventPollImpl::MAX_EVENT_POLL_HTTP_ERRORS = 10; // ~5 minutes, by the above rules.
|
||||
// We will wait RETRY_SECONDS + (errorCount * RETRY_SECONDS_INC) before retrying after an error.
|
||||
// This means we attempt to recover relatively quickly but back off giving more time to recover
|
||||
// until we finally give up after MAX_EVENT_POLL_HTTP_ERRORS attempts.
|
||||
constexpr F32 EVENT_POLL_ERROR_RETRY_SECONDS = 15.f; // ~ half of a normal timeout.
|
||||
constexpr F32 EVENT_POLL_ERROR_RETRY_SECONDS_INC = 5.f; // ~ half of a normal timeout.
|
||||
constexpr S32 MAX_EVENT_POLL_HTTP_ERRORS = 10; // ~5 minutes, by the above rules.
|
||||
constexpr F64 MIN_SECONDS_PASSED = 10.0; // Minimum time we expect the server to hold the request.
|
||||
|
||||
int LLEventPollImpl::sNextCounter = 1;
|
||||
|
||||
|
|
@ -91,7 +87,6 @@ namespace Details
|
|||
mDone(false),
|
||||
mHttpRequest(),
|
||||
mHttpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID),
|
||||
mHttpOptions(), // <FS:Ansariel> Restore pre-coro behavior (60s timeout, no retries)
|
||||
mSenderIp(),
|
||||
mCounter(sNextCounter++)
|
||||
|
||||
|
|
@ -100,16 +95,6 @@ namespace Details
|
|||
|
||||
mHttpRequest = LLCore::HttpRequest::ptr_t(new LLCore::HttpRequest);
|
||||
mHttpPolicy = app_core_http.getPolicy(LLAppCoreHttp::AP_LONG_POLL);
|
||||
// <FS:Ansariel> Restore pre-coro behavior (60s timeout, no retries)
|
||||
mHttpOptions = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
|
||||
#ifdef OPENSIM
|
||||
if (LLGridManager::instance().isInOpenSim())
|
||||
{
|
||||
mHttpOptions->setRetries(0);
|
||||
mHttpOptions->setTransferTimeout(60);
|
||||
}
|
||||
#endif
|
||||
// </FS:Ansariel>
|
||||
mSenderIp = sender.getIPandPort();
|
||||
}
|
||||
|
||||
|
|
@ -122,13 +107,11 @@ namespace Details
|
|||
{
|
||||
message["sender"] = mSenderIp;
|
||||
// <FS:ND> Guard against messages with no "body"
|
||||
|
||||
// message["body"] = content["body"];
|
||||
|
||||
if( content.has( "body" ) )
|
||||
if (content.has("body"))
|
||||
message["body"] = content["body"];
|
||||
else
|
||||
LL_WARNS() << "Malformed content? " << ll_pretty_print_sd( content ) << LL_ENDL;
|
||||
LL_WARNS() << "Malformed content? " << ll_pretty_print_sd(content) << LL_ENDL;
|
||||
// <FS:ND>
|
||||
}
|
||||
catch (std::bad_alloc&)
|
||||
|
|
@ -174,11 +157,25 @@ namespace Details
|
|||
LLSD acknowledge;
|
||||
int errorCount = 0;
|
||||
int counter = mCounter; // saved on the stack for logging.
|
||||
LLTimer message_time;
|
||||
|
||||
LL_DEBUGS("LLEventPollImpl") << " <" << counter << "> entering coroutine." << LL_ENDL;
|
||||
|
||||
mAdapter = httpAdapter;
|
||||
|
||||
// This is a loop with its own waitToRetry implementation,
|
||||
// so disable retries.
|
||||
LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
|
||||
httpOpts->setRetries(0);
|
||||
// <FS:Ansariel> Restore pre-coro behavior (60s timeout, no retries)
|
||||
#ifdef OPENSIM
|
||||
if (LLGridManager::instance().isInOpenSim())
|
||||
{
|
||||
httpOpts->setTransferTimeout(60);
|
||||
}
|
||||
#endif
|
||||
// </FS:Ansariel>
|
||||
|
||||
LL::WorkQueue::ptr_t main_queue = nullptr;
|
||||
|
||||
// HACK -- grab the mainloop workqueue to move execution of the handler
|
||||
|
|
@ -195,14 +192,13 @@ namespace Details
|
|||
request["ack"] = acknowledge;
|
||||
request["done"] = mDone;
|
||||
|
||||
message_time.reset();
|
||||
|
||||
// LL_DEBUGS("LLEventPollImpl::eventPollCoro") << "<" << counter << "> request = "
|
||||
// << LLSDXMLStreamer(request) << LL_ENDL;
|
||||
|
||||
LL_DEBUGS("LLEventPollImpl") << " <" << counter << "> posting and yielding." << LL_ENDL;
|
||||
// <FS:Ansariel> Restore pre-coro behavior (60s timeout, no retries)
|
||||
//LLSD result = httpAdapter->postAndSuspend(mHttpRequest, url, request);
|
||||
LLSD result = httpAdapter->postAndSuspend(mHttpRequest, url, request, mHttpOptions);
|
||||
// </FS:Ansariel>
|
||||
LLSD result = httpAdapter->postAndSuspend(mHttpRequest, url, request, httpOpts);
|
||||
|
||||
// LL_DEBUGS("LLEventPollImpl::eventPollCoro") << "<" << counter << "> result = "
|
||||
// << LLSDXMLStreamer(result) << LL_ENDL;
|
||||
|
|
@ -220,11 +216,30 @@ namespace Details
|
|||
|
||||
if (!status)
|
||||
{
|
||||
if (status == LLCore::HttpStatus(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_OPERATION_TIMEDOUT))
|
||||
{ // A standard timeout response we get this when there are no events.
|
||||
LL_DEBUGS("LLEventPollImpl") << "All is very quiet on target server. It may have gone idle?" << LL_ENDL;
|
||||
errorCount = 0;
|
||||
continue;
|
||||
if (status == LLCore::HttpStatus(LLCore::HttpStatus::EXT_CURL_EASY, CURLE_OPERATION_TIMEDOUT) // A standard timeout, no events.
|
||||
|| status == LLCore::HttpStatus(HTTP_BAD_GATEWAY) // An expected 'No events' case.
|
||||
|| status == LLCore::HttpStatus(HTTP_INTERNAL_ERROR)
|
||||
|| status == LLCore::HttpStatus(HTTP_SERVICE_UNAVAILABLE)
|
||||
|| status == LLCore::HttpStatus(HTTP_GATEWAY_TIME_OUT))
|
||||
{
|
||||
if (message_time.getElapsedSeconds() < MIN_SECONDS_PASSED)
|
||||
{
|
||||
// Server is supposed to hold request for 20 to 30 seconds.
|
||||
// If it didn't hold the request at least for 10s, treat as an error.
|
||||
LL_WARNS("LLEventPollImpl") << "Response arrived too early, status: " << status.toTerseString()
|
||||
<< ", time passed: " << message_time.getElapsedSeconds() << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Timeout, expected and means 'no events'. Request is to be re-issued immediately.
|
||||
// Current definition of a timeout is any of :
|
||||
// - libcurl easy 28 status code
|
||||
// - Linden 499 special http status code
|
||||
// - RFC - standard 502 - 504 http status codes
|
||||
LL_DEBUGS("LLEventPollImpl") << "No events, from: " << mSenderIp <<" status: " << (S32)status.getStatus() << LL_ENDL;
|
||||
errorCount = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// <FS:Ansariel> Restore pre-coro behavior (60s timeout, no retries)
|
||||
#ifdef OPENSIM
|
||||
|
|
@ -243,13 +258,13 @@ namespace Details
|
|||
// some cases the server gets ahead of the viewer and will
|
||||
// return a 404 error (Not Found) before the cancel event
|
||||
// comes back in the queue
|
||||
LL_WARNS("LLEventPollImpl") << "Canceling coroutine" << LL_ENDL;
|
||||
LL_WARNS("LLEventPollImpl") << "<" << counter << "> Canceling coroutine, status: " << status.toTerseString() << LL_ENDL;
|
||||
break;
|
||||
}
|
||||
else if (!status.isHttpStatus())
|
||||
{
|
||||
/// Some LLCore or LIBCurl error was returned. This is unlikely to be recoverable
|
||||
LL_WARNS("LLEventPollImpl") << "Critical error from poll request returned from libraries. Canceling coroutine." << LL_ENDL;
|
||||
LL_WARNS("LLEventPollImpl") << "<" << counter << "> Critical error from poll request returned from libraries. Canceling coroutine." << LL_ENDL;
|
||||
break;
|
||||
}
|
||||
LL_WARNS("LLEventPollImpl") << "<" << counter << "> Error result from LLCoreHttpUtil::HttpCoroHandler. Code "
|
||||
|
|
@ -292,6 +307,10 @@ namespace Details
|
|||
LL_WARNS("LLEventPollImpl") << "< " << counter << "> Forcing disconnect due to stalled main region event poll." << LL_ENDL;
|
||||
LLAppViewer::instance()->forceDisconnect(LLTrans::getString("AgentLostConnection"));
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("LLEventPollImpl") << "< " << counter << "> Stopping event poll for " << mSenderIp << " due to failures." << LL_ENDL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,30 @@ namespace Details
|
|||
|
||||
|
||||
class LLEventPoll
|
||||
///< implements the viewer side of server-to-viewer pushed events.
|
||||
///< Implements the viewer side of server-to-viewer pushed events.
|
||||
///
|
||||
/// This class implements the sole consumer of the EventQueueGet capability
|
||||
/// and delivers data, including llsd-encoded llmessage payloads, from
|
||||
/// simulator to viewer.
|
||||
///
|
||||
/// https://wiki.secondlife.com/wiki/EventQueueGet
|
||||
/// The wiki page is neither complete nor entirely correct. Request timeouts
|
||||
/// became the de facto method of returning an empty event set to the viewer.
|
||||
/// But the timeout behavior was never defined. It was simply whatever
|
||||
/// behavior a given grid implementation implemented.
|
||||
///
|
||||
/// In SL's case, the path may include reverse proxies, http caches, http and
|
||||
/// socks proxies, transparent hijacking, and other horrors. A pitfall for
|
||||
/// implementors.
|
||||
///
|
||||
/// Current definition of a timeout is any of :
|
||||
/// - libcurl easy 28 status code
|
||||
/// - Linden 499 special http status code
|
||||
/// - RFC - standard 502 - 504 http status codes
|
||||
/// If requests are failing too quickly with the above errors, they are treated
|
||||
/// as actual errors and not an empty payload. These will count towards a final
|
||||
/// error declaration and can lead to disconnection from a simulator or the
|
||||
/// entire grid.
|
||||
{
|
||||
public:
|
||||
LLEventPoll(const std::string& pollURL, const LLHost& sender);
|
||||
|
|
|
|||
|
|
@ -2421,6 +2421,7 @@ void LLFloaterPreference::onChangeQuality(const LLSD& data)
|
|||
}
|
||||
mLastQualityLevel = level;
|
||||
LLFeatureManager::getInstance()->setGraphicsLevel(level, true);
|
||||
gSavedSettings.setU32("DebugQualityPerformance", level);
|
||||
refreshEnabledGraphics();
|
||||
refresh();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -240,13 +240,38 @@ void LLPanelVoiceDeviceSettings::refresh()
|
|||
if(mCtrlInputDevices)
|
||||
{
|
||||
mCtrlInputDevices->removeall();
|
||||
mCtrlInputDevices->add(getLocalizedDeviceName(mInputDevice), mInputDevice, ADD_BOTTOM);
|
||||
auto it = mLocalizedDeviceNames.find(mInputDevice);
|
||||
if (it != mLocalizedDeviceNames.end())
|
||||
{
|
||||
mCtrlInputDevices->add(getLocalizedDeviceName(mInputDevice), mInputDevice, ADD_BOTTOM);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Display name generaly doesn't match value.
|
||||
// Value is an id so it's not nessesary readable,
|
||||
// might not even be valid (disconnected usb).
|
||||
// Until we get the data, don't change the device,
|
||||
// otherwise box might override the control.
|
||||
// But show a readable placeholder.
|
||||
// Combo is disabled so it's safe to show
|
||||
// a placeholder.
|
||||
mCtrlInputDevices->add(getString("device_not_loaded"), mInputDevice, ADD_BOTTOM);
|
||||
}
|
||||
mCtrlInputDevices->setValue(mInputDevice);
|
||||
}
|
||||
if(mCtrlOutputDevices)
|
||||
{
|
||||
mCtrlOutputDevices->removeall();
|
||||
mCtrlOutputDevices->add(getLocalizedDeviceName(mOutputDevice), mOutputDevice, ADD_BOTTOM);
|
||||
auto it = mLocalizedDeviceNames.find(mOutputDevice);
|
||||
if (it != mLocalizedDeviceNames.end())
|
||||
{
|
||||
mCtrlOutputDevices->add(getLocalizedDeviceName(mOutputDevice), mOutputDevice, ADD_BOTTOM);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't change the device, only the label
|
||||
mCtrlOutputDevices->add(getString("device_not_loaded"), mOutputDevice, ADD_BOTTOM);
|
||||
}
|
||||
mCtrlOutputDevices->setValue(mOutputDevice);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,7 +152,11 @@ void LLFloaterSettingsPicker::onClose(bool app_quitting)
|
|||
owner->setFocus(true);
|
||||
}
|
||||
mSettingItemID.setNull();
|
||||
mInventoryPanel->getRootFolder()->clearSelection();
|
||||
mInventoryPanel->clearSelection();
|
||||
if (mInventoryPanel->getRootFolder())
|
||||
{
|
||||
mInventoryPanel->getRootFolder()->clearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
void LLFloaterSettingsPicker::setValue(const LLSD& value)
|
||||
|
|
|
|||
|
|
@ -696,7 +696,26 @@ bool idle_startup()
|
|||
system = osString.substr (begIdx, endIdx - begIdx);
|
||||
system += "Locale";
|
||||
|
||||
LLStringUtil::setLocale (LLTrans::getString(system));
|
||||
std::string locale = LLTrans::getString(system);
|
||||
if (locale != LLStringUtil::getLocale()) // is there a reason to do this on repeat?
|
||||
{
|
||||
LLStringUtil::setLocale(locale);
|
||||
|
||||
// Not all locales have AMPM, test it
|
||||
if (LLStringOps::sAM.empty()) // Might already be overriden from LLAppViewer::init()
|
||||
{
|
||||
LLDate datetime(0.0);
|
||||
std::string val = datetime.toHTTPDateString("%p");
|
||||
if (val.empty())
|
||||
{
|
||||
LL_DEBUGS("InitInfo") << "Current locale \"" << locale << "\" "
|
||||
<< "doesn't support AM/PM time format" << LL_ENDL;
|
||||
// fallback to declarations in strings.xml
|
||||
LLStringOps::sAM = LLTrans::getString("dateTimeAM");
|
||||
LLStringOps::sPM = LLTrans::getString("dateTimePM");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//note: Removing this line will cause incorrect button size in the login screen. -- bao.
|
||||
gTextureList.updateImages(0.01f) ;
|
||||
|
|
|
|||
|
|
@ -1081,6 +1081,8 @@ void LLFloaterTexturePicker::onBtnSetToDefault(void* userdata)
|
|||
{
|
||||
self->setImageID( self->getDefaultImageAssetID() );
|
||||
self->setTentative(false);
|
||||
// Deselect in case inventory has a selected item with the same id
|
||||
self->mInventoryPanel->getRootFolder()->clearSelection();
|
||||
}
|
||||
self->commitIfImmediateSet();
|
||||
}
|
||||
|
|
@ -1092,6 +1094,8 @@ void LLFloaterTexturePicker::onBtnBlank(void* userdata)
|
|||
self->setCanApply(true, true);
|
||||
self->setImageID( self->getBlankImageAssetID() );
|
||||
self->setTentative(false);
|
||||
// Deselect in case inventory has a selected item with the same id
|
||||
self->mInventoryPanel->getRootFolder()->clearSelection();
|
||||
self->commitIfImmediateSet();
|
||||
}
|
||||
|
||||
|
|
@ -1113,6 +1117,8 @@ void LLFloaterTexturePicker::onBtnNone(void* userdata)
|
|||
self->setCanApply(true, true);
|
||||
self->setImageID( LLUUID::null );
|
||||
self->setTentative(false);
|
||||
// Deselect in case inventory has a selected item with null id
|
||||
self->mInventoryPanel->getRootFolder()->clearSelection();
|
||||
self->commitIfImmediateSet();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@
|
|||
#include "llrender.h"
|
||||
#include "llnavigationbar.h"
|
||||
#include "llnotificationsutil.h"
|
||||
#include "llfloaterpreference.h"
|
||||
#include "llfloaterreg.h"
|
||||
#include "llfloatertools.h"
|
||||
#include "llpaneloutfitsinventory.h"
|
||||
// <FS:Ansariel> [FS Login Panel]
|
||||
|
|
@ -229,6 +231,21 @@ static bool handleDebugAvatarJointsChanged(const LLSD& newvalue)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool handleDebugQualityPerformanceChanged(const LLSD& newvalue)
|
||||
{
|
||||
// control was set directly or after adjusting Preference setting, no need to update
|
||||
if (gSavedSettings.getU32("RenderQualityPerformance") != gSavedSettings.getU32("DebugQualityPerformance"))
|
||||
{
|
||||
LLFloaterPreference* instance = LLFloaterReg::getTypedInstance<LLFloaterPreference>("preferences");
|
||||
if (instance)
|
||||
{
|
||||
gSavedSettings.setU32("RenderQualityPerformance", newvalue.asInteger());
|
||||
instance->onChangeQuality(newvalue);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool handleAvatarHoverOffsetChanged(const LLSD& newvalue)
|
||||
{
|
||||
if (isAgentAvatarValid())
|
||||
|
|
@ -1420,6 +1437,7 @@ void settings_setup_listeners()
|
|||
setting_setup_signal_listener(gSavedSettings, "SpellCheckDictionary", handleSpellCheckChanged);
|
||||
setting_setup_signal_listener(gSavedSettings, "LoginLocation", handleLoginLocationChanged);
|
||||
setting_setup_signal_listener(gSavedSettings, "DebugAvatarJoints", handleDebugAvatarJointsChanged);
|
||||
setting_setup_signal_listener(gSavedSettings, "DebugQualityPerformance", handleDebugQualityPerformanceChanged);
|
||||
|
||||
setting_setup_signal_listener(gSavedSettings, "TargetFPS", handleTargetFPSChanged);
|
||||
setting_setup_signal_listener(gSavedSettings, "AutoTuneFPS", handleAutoTuneFPSChanged);
|
||||
|
|
|
|||
|
|
@ -8096,7 +8096,7 @@ bool handle_zoom_to_object(const LLUUID& object_id, const std::optional<LLVector
|
|||
|
||||
LLViewerObject* object = gObjectList.findObject(object_id);
|
||||
|
||||
if (object)
|
||||
if (object && object->isReachable())
|
||||
{
|
||||
gAgentCamera.setFocusOnAvatar(false, ANIMATE);
|
||||
|
||||
|
|
|
|||
|
|
@ -8026,6 +8026,51 @@ void LLViewerObject::clearTEWaterExclusion(const U8 te)
|
|||
}
|
||||
}
|
||||
|
||||
bool LLViewerObject::isReachable()
|
||||
{
|
||||
LLViewerRegion* agent_region = gAgent.getRegion();
|
||||
LLViewerRegion* object_region = getRegion();
|
||||
|
||||
if (!agent_region || !object_region)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (agent_region == object_region)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unordered_set<LLViewerRegion*> visited;
|
||||
std::queue<LLViewerRegion*> pending;
|
||||
visited.insert(agent_region);
|
||||
pending.push(agent_region);
|
||||
|
||||
while (!pending.empty())
|
||||
{
|
||||
LLViewerRegion* current = pending.front();
|
||||
pending.pop();
|
||||
|
||||
std::vector<LLViewerRegion*> neighbors;
|
||||
current->getNeighboringRegions(neighbors);
|
||||
|
||||
for (LLViewerRegion* neighbor : neighbors)
|
||||
{
|
||||
if (!neighbor) continue;
|
||||
|
||||
if (neighbor == object_region)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// region's neighbors were not checked
|
||||
if (visited.insert(neighbor).second)
|
||||
{
|
||||
pending.push(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
class ObjectPhysicsProperties : public LLHTTPNode
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -266,6 +266,9 @@ public:
|
|||
// Accessor functions
|
||||
LLViewerRegion* getRegion() const { return mRegionp; }
|
||||
|
||||
// Check if object is reachable from agent region by traversing loaded neighboring regions
|
||||
bool isReachable();
|
||||
|
||||
bool isSelected() const { return mUserSelected; }
|
||||
// Check whole linkset
|
||||
bool isAnySelected() const;
|
||||
|
|
|
|||
|
|
@ -1568,18 +1568,43 @@ void LLViewerWindow::handleMouseLeave(LLWindow *window)
|
|||
LLToolTipMgr::instance().blockToolTips();
|
||||
}
|
||||
|
||||
bool LLViewerWindow::handleCloseRequest(LLWindow *window)
|
||||
bool LLViewerWindow::handleCloseRequest(LLWindow *window, bool from_user)
|
||||
{
|
||||
if (!LLApp::isExiting() && !LLApp::isStopped())
|
||||
{
|
||||
// User has indicated they want to close, but we may need to ask
|
||||
// about modified documents.
|
||||
LLAppViewer::instance()->userQuit();
|
||||
// Don't quit immediately
|
||||
if (from_user)
|
||||
{
|
||||
// User has indicated they want to close, but we may need to ask
|
||||
// about modified documents.
|
||||
LLAppViewer::instance()->userQuit();
|
||||
// Don't quit immediately
|
||||
}
|
||||
else
|
||||
{
|
||||
// OS is asking us to quit, assume we have time and start cleanup
|
||||
LLAppViewer::instance()->requestQuit();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LLViewerWindow::handleSessionExit(LLWindow* window)
|
||||
{
|
||||
if (!LLApp::isExiting() && !LLApp::isStopped())
|
||||
{
|
||||
// Viewer received WM_ENDSESSION and app will be killed soon if it doesn't respond
|
||||
LLAppViewer* app = LLAppViewer::instance();
|
||||
app->sendSimpleLogoutRequest();
|
||||
app->earlyExitNoNotify();
|
||||
|
||||
// Not viewer's fault, remove marker files so
|
||||
// that statistics won't consider this to be a crash
|
||||
app->removeMarkerFiles();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLViewerWindow::handleQuit(LLWindow *window)
|
||||
{
|
||||
if (gNonInteractive)
|
||||
|
|
|
|||
|
|
@ -199,7 +199,8 @@ public:
|
|||
/*virtual*/ bool handleUnicodeChar(llwchar uni_char, MASK mask); // NOT going to handle extended
|
||||
/*virtual*/ bool handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask);
|
||||
/*virtual*/ bool handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask);
|
||||
/*virtual*/ bool handleCloseRequest(LLWindow *window);
|
||||
/*virtual*/ bool handleCloseRequest(LLWindow *window, bool from_user);
|
||||
/*virtual*/ bool handleSessionExit(LLWindow* window);
|
||||
/*virtual*/ void handleQuit(LLWindow *window);
|
||||
/*virtual*/ bool handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK mask);
|
||||
/*virtual*/ bool handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask);
|
||||
|
|
|
|||
|
|
@ -288,6 +288,8 @@ void LLWebRTCVoiceClient::terminate()
|
|||
return;
|
||||
}
|
||||
|
||||
LL_INFOS("Voice") << "Terminating WebRTC" << LL_ENDL;
|
||||
|
||||
mVoiceEnabled = false;
|
||||
llwebrtc::terminate();
|
||||
|
||||
|
|
|
|||
|
|
@ -12115,21 +12115,24 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
// Called from LLViewHighlightTransparent when "Highlight Transparent" is toggled
|
||||
void LLPipeline::rebuildDrawInfo()
|
||||
{
|
||||
for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
|
||||
iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
|
||||
const U32 types_to_traverse[] =
|
||||
{
|
||||
LLViewerRegion* region = *iter;
|
||||
LLViewerRegion::PARTITION_VOLUME,
|
||||
LLViewerRegion::PARTITION_BRIDGE,
|
||||
LLViewerRegion::PARTITION_AVATAR
|
||||
};
|
||||
|
||||
LLOctreeDirty dirty;
|
||||
|
||||
LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_VOLUME);
|
||||
dirty.traverse(part->mOctree);
|
||||
|
||||
part = region->getSpatialPartition(LLViewerRegion::PARTITION_BRIDGE);
|
||||
dirty.traverse(part->mOctree);
|
||||
LLOctreeDirty dirty;
|
||||
for (LLViewerRegion* region : LLWorld::getInstance()->getRegionList())
|
||||
{
|
||||
for (U32 type : types_to_traverse)
|
||||
{
|
||||
LLSpatialPartition* part = region->getSpatialPartition(type);
|
||||
dirty.traverse(part->mOctree);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@
|
|||
<string name="name_default_system_device">
|
||||
Standardsystemgerät
|
||||
</string>
|
||||
<string name="device_not_loaded">
|
||||
Gerät nicht geladen
|
||||
</string>
|
||||
<text name="Input">
|
||||
Eingabe
|
||||
</text>
|
||||
|
|
|
|||
|
|
@ -24,6 +24,10 @@
|
|||
name="name_default_system_device">
|
||||
Default System Device
|
||||
</string>
|
||||
<string
|
||||
name="device_not_loaded">
|
||||
Device not loaded
|
||||
</string>
|
||||
<icon
|
||||
follows="left|top"
|
||||
height="18"
|
||||
|
|
|
|||
Loading…
Reference in New Issue