diff options
| author | Erik Kundiman <erik@megapahit.org> | 2026-03-30 17:10:44 +0800 |
|---|---|---|
| committer | Erik Kundiman <erik@megapahit.org> | 2026-03-30 17:10:44 +0800 |
| commit | 14239ba6f6d4a73038a270de5d8f295fb59498bd (patch) | |
| tree | b64cb90623d9cf4709fc2bec5a51b4c99a421a4a | |
| parent | eac10375e294cd24c21c09497e838e70dcf4d74a (diff) | |
| parent | f148dbcc8a9566f1f717fdeb00813ad57427bee7 (diff) | |
Merge tag 'Second_Life_Release#f148dbcc-26.2' into 2026.02
| -rw-r--r-- | indra/llcommon/llapp.h | 1 | ||||
| -rw-r--r-- | indra/llcommon/llwatchdog.cpp | 70 | ||||
| -rw-r--r-- | indra/llcommon/llwatchdog.h | 25 | ||||
| -rw-r--r-- | indra/llprimitive/llgltfmaterial.cpp | 65 | ||||
| -rw-r--r-- | indra/newview/llappviewer.cpp | 143 | ||||
| -rw-r--r-- | indra/newview/llappviewer.h | 3 | ||||
| -rw-r--r-- | indra/newview/llappviewerwin32.cpp | 50 | ||||
| -rw-r--r-- | indra/newview/llappviewerwin32.h | 1 | ||||
| -rw-r--r-- | indra/newview/llfilepicker_mac.mm | 4 | ||||
| -rw-r--r-- | indra/newview/llvoiceclient.cpp | 10 | ||||
| -rw-r--r-- | indra/newview/llworldmapmessage.cpp | 1 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/strings.xml | 3 |
12 files changed, 314 insertions, 62 deletions
diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index ce09c566a9..fef7dc80b3 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -285,6 +285,7 @@ public: #ifdef LL_WINDOWS virtual bool reportCrashToBugsplat(void* pExcepInfo /*EXCEPTION_POINTERS*/) { return false; } + virtual bool reportCustomToBugsplat(const std::string& desription) { return false; } #endif public: diff --git a/indra/llcommon/llwatchdog.cpp b/indra/llcommon/llwatchdog.cpp index 1bc1283d0b..1622aeb180 100644 --- a/indra/llcommon/llwatchdog.cpp +++ b/indra/llcommon/llwatchdog.cpp @@ -87,7 +87,7 @@ void LLWatchdogEntry::start() void LLWatchdogEntry::stop() { // this can happen very late in the shutdown sequence - if (!LLWatchdog::wasDeleted()) + if (LLWatchdog::instanceExists()) { LLWatchdog::getInstance()->remove(this); } @@ -173,6 +173,17 @@ void LLWatchdog::add(LLWatchdogEntry* e) { lockThread(); mSuspects.insert(e); + + if (!mFrozeList.empty()) + { + mFrozeList.erase(e); + if (mFrozeList.empty()) + { + // Clear error marker file if there is no frozen threads, + // viewer is responsive again. + mClearMarkerFnc(); + } + } unlockThread(); } @@ -183,7 +194,12 @@ void LLWatchdog::remove(LLWatchdogEntry* e) unlockThread(); } -void LLWatchdog::init(func_t set_error_state_callback) +void LLWatchdog::init( + create_marker_func_t error_state_callback, + clear_marker_func_t clear_marker_callback, + report_func_t report_callback, + notify_func_t notify_callback, + bool crash_on_freeze) { if (!mSuspectsAccessMutex && !mTimer) { @@ -196,7 +212,11 @@ void LLWatchdog::init(func_t set_error_state_callback) // start needs to use the mSuspectsAccessMutex mTimer->start(); } - mCreateMarkerFnc = set_error_state_callback; + mCreateMarkerFnc = error_state_callback; + mClearMarkerFnc = clear_marker_callback; + mCrashReportFnc = report_callback; + mNotifyFnc = notify_callback; + mCrashOnFreeze = crash_on_freeze; } void LLWatchdog::cleanup() @@ -251,21 +271,45 @@ void LLWatchdog::run() mTimer->stop(); } - // 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()) + std::string description = "Watchdog timer for thread " + (*result)->getThreadName() + " expired"; + if (!last_state.empty()) { - LL_ERRS() << "Watchdog timer for thread " << (*result)->getThreadName() - << " expired; assuming viewer is hung and crashing" << LL_ENDL; + description += " with state: " + last_state; + } + description += "; assuming viewer is hung and crashing"; + + if (!mCrashOnFreeze) + { + // Sets watchdog marker file + mCreateMarkerFnc(false); + // If it's mainloop and it somehow recovers, it will re-add itself + mSuspects.erase(*result); + mFrozeList.insert(*result); + LL_WARNS() << description << LL_ENDL; } else { - LL_ERRS() << "Watchdog timer for thread " << (*result)->getThreadName() - << " expired with state: " << last_state - << "; assuming viewer is hung and crashing" << LL_ENDL; + + if (!mCrashReportFnc(description)) + { + // Sets error marker file + mCreateMarkerFnc(true); + // If false is returned, then we failed to report the issue to bugsplat, + // instead, Notify user, then crash viewer. + // Todo: ask user if viewer should quit or wait? + mNotifyFnc(); + LL_ERRS() << description << LL_ENDL; + } + else + { + // Sets watchdog marker file + mCreateMarkerFnc(false); + // Already reported, don't report again. + // If it's mainloop and it somehow recovers, it will re-add itself + mSuspects.erase(result); + mFrozeList.insert(*result); + } } } } diff --git a/indra/llcommon/llwatchdog.h b/indra/llcommon/llwatchdog.h index fded881bb8..f138fbccb0 100644 --- a/indra/llcommon/llwatchdog.h +++ b/indra/llcommon/llwatchdog.h @@ -83,18 +83,26 @@ private: }; class LLWatchdogTimerThread; // Defined in the cpp -class LLWatchdog : public LLSingleton<LLWatchdog> +class LLWatchdog : public LLSimpleton<LLWatchdog> { - LLSINGLETON(LLWatchdog); +public: + LLWatchdog(); ~LLWatchdog(); -public: // Add an entry to the watchdog. void add(LLWatchdogEntry* e); void remove(LLWatchdogEntry* e); - typedef std::function<void()> func_t; - void init(func_t set_error_state_callback); + typedef std::function<void(bool)> create_marker_func_t; + typedef std::function<void()> clear_marker_func_t; + typedef std::function<bool(std::string&)> report_func_t; + typedef std::function<void()> notify_func_t; + void init( + create_marker_func_t error_state_callback, + clear_marker_func_t clear_marker_callback, + report_func_t report_callback, + notify_func_t notify_callback, + bool crash_on_freeze); void run(); void cleanup(); @@ -105,14 +113,19 @@ private: typedef std::set<LLWatchdogEntry*> SuspectsRegistry; SuspectsRegistry mSuspects; + SuspectsRegistry mFrozeList; LLMutex* mSuspectsAccessMutex; LLWatchdogTimerThread* mTimer; U64 mLastClockCount; + bool mCrashOnFreeze; // 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; + create_marker_func_t mCreateMarkerFnc; + clear_marker_func_t mClearMarkerFnc; + report_func_t mCrashReportFnc; + notify_func_t mNotifyFnc; }; #endif // LL_LLTHREADWATCHDOG_H diff --git a/indra/llprimitive/llgltfmaterial.cpp b/indra/llprimitive/llgltfmaterial.cpp index 1c47001272..764ab222ad 100644 --- a/indra/llprimitive/llgltfmaterial.cpp +++ b/indra/llprimitive/llgltfmaterial.cpp @@ -937,6 +937,15 @@ void LLGLTFMaterial::updateTextureTracking() // Case 4. // Input: scale 1.0,1.0; Offset horizontal 0.5, Offset vertical 0.0 Rotation 0.349066; // Expected output: scale 1.0,1.0; Offset horizontal 0.701, Offset vertical -0.141 Rotation -0.349066; +// Case 5. +// Input: scale 10.0,15.0; Offset horizontal 0.0, Offset vertical 0.0 Rotation -1.57079637 +// Expected output: scale 15.0,10.0; Offset horizontal 7.5, Offset vertical -4.0 Rotation 1.57079637; +// Case 6. +// Input: scale 10.0,15.0; Offset horizontal 0.0, Offset vertical 0.0 Rotation 0 +// Expected output: scale 10.0,15.0; Offset horizontal 0.5, Offset vertical .0 Rotation 0; +// Case 7. +// Input: scale 10.0,15.0; Offset horizontal 0.0, Offset vertical 0.0 Rotation -0.785398163 +// Expected output: scale 12.74,12.74; Offset horizontal 0.5, Offset vertical .0 Rotation 0.785398163; // // Legacy offsets are right to left and top to bottom. // PBR offsets are right to left and bottom to top. @@ -953,16 +962,32 @@ void LLGLTFMaterial::convertTextureTransformToPBR( LLVector2& pbr_offset, F32& pbr_rotation) { - pbr_scale.set(tex_scale_s, tex_scale_t); + // Legacy is counter-clockwise, PBR is clockwise pbr_rotation = -tex_rotation; // Center of the tile const F32 center_s = 0.5f; const F32 center_t = 0.5f; + // Calculate the rotated scale + F32 cos_rot = cosf(tex_rotation); + F32 sin_rot = sinf(tex_rotation); + F32 cos_sq = cos_rot * cos_rot; + F32 sin_sq = sin_rot * sin_rot; + + // GLTF scale doesn't match legacy scaling when rotation is applied. + // Legacy applies scale then rotation, which allows for planar aligment + // withoutn deformations, but gltf rotates first, so when scale gets + // aplied image gets deformed by rotation. + // It appears to be imposible to properly match legacy scale, so this + // is an approximation that at least matches at 0, 90, 180, 270 degree + // rotations, and is close enough at angles like 45. + pbr_scale.mV[VX] = tex_scale_s * cos_sq + tex_scale_t * sin_sq; + pbr_scale.mV[VY] = tex_scale_s * sin_sq + tex_scale_t * cos_sq; + // Center adjustment for scale - F32 center_adjust_s = 0.5f * (1.0f - tex_scale_s); - F32 center_adjust_t = 0.5f * (1.0f - tex_scale_t); + F32 center_adjust_s = 0.5f * (1.0f - pbr_scale.mV[VX]); + F32 center_adjust_t = 0.5f * (1.0f - pbr_scale.mV[VY]); // 2. Offset from center F32 pos_s = center_adjust_s - center_s; @@ -990,17 +1015,43 @@ void LLGLTFMaterial::convertPBRTransformToTexture( F32& tex_offset_t, F32& tex_rotation) { - tex_scale_s = pbr_scale.mV[0]; - tex_scale_t = pbr_scale.mV[1]; tex_rotation = -pbr_rotation; + // Reverse the scale transformation + // From: pbr_s = tex_s * cos² + tex_t * sin² + // pbr_t = tex_s * sin² + tex_t * cos² + // Solve for tex_s and tex_t + F32 cos_rot = cosf(tex_rotation); + F32 sin_rot = sinf(tex_rotation); + F32 cos_sq = cos_rot * cos_rot; + F32 sin_sq = sin_rot * sin_rot; + + F32 denom = cos_sq * cos_sq - sin_sq * sin_sq; + + if (fabsf(denom) < 0.0001f) // Near 45 degrees (cos²≈sin²≈0.5) + { + // At 45°: both scales contribute equally + // pbr_s = pbr_t = (tex_s + tex_t) / 2 + // So: tex_s + tex_t = 2 * pbr_avg + // Use the average and assume symmetric scaling + tex_scale_s = tex_scale_t = (pbr_scale.mV[VX] + pbr_scale.mV[VY]) / 2.f; + } + else + { + // Solve the 2x2 system: + // pbr_s * cos² - pbr_t * sin² = tex_s * (cos⁴ - sin⁴) + // pbr_t * cos² - pbr_s * sin² = tex_t * (cos⁴ - sin⁴) + tex_scale_s = (pbr_scale.mV[VX] * cos_sq - pbr_scale.mV[VY] * sin_sq) / denom; + tex_scale_t = (pbr_scale.mV[VY] * cos_sq - pbr_scale.mV[VX] * sin_sq) / denom; + } + // Center of the tile const F32 center_s = 0.5f; const F32 center_t = 0.5f; // Center adjustment for scale - F32 center_adjust_s = 0.5f * (1.0f - tex_scale_s); - F32 center_adjust_t = 0.5f * (1.0f - tex_scale_t); + F32 center_adjust_s = 0.5f * (1.0f - pbr_scale.mV[VX]); + F32 center_adjust_t = 0.5f * (1.0f - pbr_scale.mV[VY]); // 2. Offset from center F32 pos_s = center_adjust_s - center_s; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 7653ffe424..b64b38c44f 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -390,6 +390,7 @@ const std::string MARKER_FILE_NAME("SecondLife.exec_marker"); const std::string START_MARKER_FILE_NAME("SecondLife.start_marker"); const std::string ERROR_MARKER_FILE_NAME("SecondLife.error_marker"); const std::string LOGOUT_MARKER_FILE_NAME("SecondLife.logout_marker"); +const std::string WATCHDOG_MARKER_FILE_NAME("SecondLife.watchdog_marker"); static std::string gLaunchFileOnQuit; // Used on Win32 for other apps to identify our window (eg, win_setup) @@ -984,6 +985,7 @@ bool LLAppViewer::init() // Initialize event recorder LLViewerEventRecorder::createInstance(); + LLWatchdog::createInstance(); // // Initialize the window @@ -3262,20 +3264,60 @@ bool LLAppViewer::initWindow() << " (setting = " << watchdog_enabled_setting << ")" << LL_ENDL; - if (use_watchdog) + // Watchdog reports to statistics via marker files, that is + // pointless without ability to write (!mSecondInstance) those files. + // If use_watchdog is set, watchdog also reports to bugspat. + if (use_watchdog || !mSecondInstance) { - LLWatchdog::getInstance()->init([]() - { - LLAppViewer* app = LLAppViewer::instance(); - if (app->logoutRequestSent()) + LLWatchdog::getInstance()->init( + [](bool final_marker) { - app->createErrorMarker(LAST_EXEC_LOGOUT_FROZE); - } - else + LLAppViewer* app = LLAppViewer::instance(); + // Without watchdog everything will be counted as + // either 'unknown' (no crash marker) or based of present crash marker + if (final_marker) + { + // watchdog is going to crash viewer, so crate a 'crash' marker + if (app->logoutRequestSent()) + { + app->createErrorMarker(LAST_EXEC_LOGOUT_FROZE); + } + else + { + app->createErrorMarker(LAST_EXEC_FROZE); + } + } + else + { + // not going to crash, just create a 'watchdog' marker + app->createWatchdogMarker(); + } + }, + []() { - app->createErrorMarker(LAST_EXEC_FROZE); - } - }); + LLAppViewer* app = LLAppViewer::instance(); + // in case process recovered from freeze, remove watchdog marker. + app->removeWatchdogMarker(); + }, + [](std::string &desc) + { +#if LL_WINDOWS && LL_BUGSPLAT + LLAppViewer* app = LLAppViewer::instance(); + app->writeDebugInfo(); + return app->reportCustomToBugsplat(desc); +#else + return false; +#endif + }, + []() + { + LLAppViewer* app = LLAppViewer::instance(); + app->sendLogoutRequest(); + // Might be better to ask user if user wants to terminate the app or wait. + OSMessageBox(LLTrans::getString("MBFreezeDetected"), LLTrans::getString("MBFatalError"), OSMB_OK); + }, + use_watchdog); + } LLNotificationsUI::LLNotificationManager::getInstance(); @@ -4059,13 +4101,8 @@ void LLAppViewer::processMarkerFiles() { // 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 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' + // App terminated unexpectedly or froze, we don't know the cause yet. gLastExecEvent = LAST_EXEC_UNKNOWN; -#else - gLastExecEvent = LAST_EXEC_OTHER_CRASH; -#endif // LL_WINDOWS } else @@ -4118,23 +4155,29 @@ void LLAppViewer::processMarkerFiles() } LLAPRFile::remove(logout_marker_file); } - // and last refine based on whether or not a marker created during a non-llerr crash is found + // Refine based on whether or not a marker created during + // a crash is found or if wathdog caught a freeze. + // Bugsplat will set correct state in bugsplatSendLog. std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME); + std::string watchdog_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, WATCHDOG_MARKER_FILE_NAME); if(LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB)) { S32 marker_code = getMarkerErrorCode(error_marker_file); if (marker_code >= 0) { - if (gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) - { - gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; - LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL; - } - else if (marker_code > 0 && marker_code < (S32)LAST_EXEC_COUNT) + if (marker_code > 0 && marker_code < (S32)LAST_EXEC_COUNT) { + // If we have a code, it takes precendence gLastExecEvent = (eLastExecEvent)marker_code; LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL; } + // if we have the marker, even without a code, it's a crash. + else if (gLastExecEvent == LAST_EXEC_LOGOUT_UNKNOWN + || gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) + { + gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; + LL_INFOS("MarkerFile") << "Error marker '" << error_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL; + } else { gLastExecEvent = LAST_EXEC_OTHER_CRASH; @@ -4146,6 +4189,33 @@ void LLAppViewer::processMarkerFiles() LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' marker found, but versions did not match" << LL_ENDL; } LLAPRFile::remove(error_marker_file); + if (LLAPRFile::isExist(watchdog_marker_file, NULL, LL_APR_RB)) + { + // If viewer crashed after a freeze was detected, + // crash still takes precendence. Just clear watchdog. + removeWatchdogMarker(); + } + } + else + { + // so only check watchdog marker if there is no error marker. + if (LLAPRFile::isExist(watchdog_marker_file, NULL, LL_APR_RB)) + { + if (LAST_EXEC_UNKNOWN == gLastExecEvent + || LAST_EXEC_LOGOUT_UNKNOWN == gLastExecEvent) + { + // watchdog marker gets created if we detect a freeze, + // so if viwer did not stop gracefully, and we know it wasn't a crash, + // we have no other info, check watchdog. + if (markerIsSameVersion(watchdog_marker_file)) + { + gLastExecEvent = LAST_EXEC_UNKNOWN == gLastExecEvent ? LAST_EXEC_FROZE : LAST_EXEC_LOGOUT_FROZE; + LL_INFOS("MarkerFile") << "Watchdog marker '" << watchdog_marker_file << "' found, setting LastExecEvent to FROZE" + << LL_ENDL; + } + } + removeWatchdogMarker(); + } } #if LL_DARWIN @@ -4190,6 +4260,7 @@ void LLAppViewer::removeMarkerFiles() { LL_WARNS("MarkerFile") << "logout marker '"<<mLogoutMarkerFileName<<"' not open"<< LL_ENDL; } + removeWatchdogMarker(); } else { @@ -5577,6 +5648,30 @@ bool LLAppViewer::errorMarkerExists() const return LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB); } +void LLAppViewer::createWatchdogMarker() const +{ + if (!mSecondInstance) + { + std::string error_marker = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, WATCHDOG_MARKER_FILE_NAME); + + LLAPRFile file; + file.open(error_marker, LL_APR_WB); + if (file.getFileHandle()) + { + recordMarkerVersion(file); + file.close(); + } + } +} +void LLAppViewer::removeWatchdogMarker() const +{ + if (!mSecondInstance) + { + std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, WATCHDOG_MARKER_FILE_NAME); + LLFile::remove(error_marker_file); + } +} + void LLAppViewer::outOfMemorySoftQuit() { if (!mQuitRequested) diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index e1119419af..71033b6d3f 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -257,6 +257,9 @@ public: void createErrorMarker(eLastExecEvent error_code) const; bool errorMarkerExists() const; + void createWatchdogMarker() const; + void removeWatchdogMarker() const; + // Attempt a 'soft' quit with disconnect and saving of settings/cache. // Intended to be thread safe. // Good chance of viewer crashing either way, but better than alternatives. diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 5288dce69c..c6ecc43198 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -118,6 +118,7 @@ namespace // MiniDmpSender pointer. As things stand, though, we must define an // actual function and store the pointer statically. static MiniDmpSender *sBugSplatSender = nullptr; + static std::string sBugsplatDesriptionField; bool bugsplatSendLog(UINT nCode, LPVOID lpVal1, LPVOID lpVal2) { @@ -154,8 +155,21 @@ namespace WCSTR(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "settings_per_account.xml"))); } - // LL_ERRS message, when there is one - sBugSplatSender->setDefaultUserDescription(WCSTR(LLError::getFatalMessage())); + if (!sBugsplatDesriptionField.empty()) + { + // Can be set by watchdog or other code that detects a problem + // and wants to add some context to the crash report. + // Will be visible in the BugSplat web UI. + sBugSplatSender->setDefaultUserDescription(WCSTR(LLError::getFatalMessage())); + // This type of crash is not nessesarily a crash, or final. + // Prepare for the next one. + sBugsplatDesriptionField.clear(); + } + else + { + // LL_ERRS message, when there is one + sBugSplatSender->setDefaultUserDescription(WCSTR(LLError::getFatalMessage())); + } sBugSplatSender->setAttribute(WCSTR(L"OS"), WCSTR(LLOSInfo::instance().getOSStringSimple())); // In case we ever stop using email for this sBugSplatSender->setAttribute(WCSTR(L"AppState"), WCSTR(LLStartUp::getStartupStateString())); @@ -849,6 +863,38 @@ bool LLAppViewerWin32::reportCrashToBugsplat(void* pExcepInfo) return false; } +#if defined(LL_BUGSPLAT) +static int reportCustomToBugsplatFilter(EXCEPTION_POINTERS* pExcepInfo) +{ + if (sBugSplatSender) + { + sBugSplatSender->createReport(pExcepInfo); + } + return EXCEPTION_EXECUTE_HANDLER; +} +#endif + +bool LLAppViewerWin32::reportCustomToBugsplat(const std::string &description) +{ +#if defined(LL_BUGSPLAT) + if (sBugSplatSender) + { + sBugsplatDesriptionField = description; + + __try + { + // Generate a custom exception code + RaiseException(0xE0000001, 0, 0, NULL); + } + __except (reportCustomToBugsplatFilter(GetExceptionInformation())) + { + } + return true; + } +#endif // LL_BUGSPLAT + return false; +} + bool LLAppViewerWin32::initWindow() { // This is a workaround/hotfix for a change in Windows 11 24H2 (and possibly later) diff --git a/indra/newview/llappviewerwin32.h b/indra/newview/llappviewerwin32.h index 3fad53ec72..5abcca1ce9 100644 --- a/indra/newview/llappviewerwin32.h +++ b/indra/newview/llappviewerwin32.h @@ -44,6 +44,7 @@ public: bool cleanup() override; bool reportCrashToBugsplat(void* pExcepInfo) override; + bool reportCustomToBugsplat(const std::string& desription) override; protected: bool initWindow() override; // Override to initialize the viewer's window. diff --git a/indra/newview/llfilepicker_mac.mm b/indra/newview/llfilepicker_mac.mm index 7262d18483..99e93bafbf 100644 --- a/indra/newview/llfilepicker_mac.mm +++ b/indra/newview/llfilepicker_mac.mm @@ -245,8 +245,8 @@ void doSaveDialogModeless(const std::string* file, NSURL *last_url = [[NSUserDefaults standardUserDefaults] URLForKey:@"NSNavLastRootDirectory"]; if(!last_url) { - NSURL *documents_url = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask].firstObject; - [panel setDirectoryURL:documents_url]; + NSURL *downloads_url = [[NSFileManager defaultManager] URLsForDirectory:NSDownloadsDirectory inDomains:NSUserDomainMask].firstObject; + [panel setDirectoryURL:downloads_url]; } [panel beginWithCompletionHandler:^(NSModalResponse result) diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 91d5451bff..4fd0a8e2b8 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -749,6 +749,9 @@ void LLVoiceClient::setUserPTTState(bool ptt) { if (ptt) { + // Nearby chat is muted by moderator, don't toggle PTT + if (!mUserPTTState && LLNearbyVoiceModeration::getInstance()->showNotificationIfNeeded()) + return; LLUIUsage::instance().logCommand("Agent.EnableMicrophone"); } mUserPTTState = ptt; @@ -793,13 +796,6 @@ bool LLVoiceClient::getPTTIsToggle() void LLVoiceClient::inputUserControlState(bool down) { - if (down && !getUserPTTState()) - { - // Nearby chat is muted by moderator, don't toggle PTT - if (LLNearbyVoiceModeration::getInstance()->showNotificationIfNeeded()) - return; - } - if(mPTTIsToggle) { if(down) // toggle open-mic state on 'down' diff --git a/indra/newview/llworldmapmessage.cpp b/indra/newview/llworldmapmessage.cpp index a5433133ab..3264f8ae8b 100644 --- a/indra/newview/llworldmapmessage.cpp +++ b/indra/newview/llworldmapmessage.cpp @@ -34,7 +34,6 @@ #include "llfloaterworldmap.h" constexpr U32 LAYER_FLAG = 2; -constexpr S32 MAP_SIM_RETURN_NULL_SIMS = 0x00010000; //--------------------------------------------------------------------------- // World Map Message Handling diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 82dcbf2d30..63369431b1 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -3008,6 +3008,9 @@ If this message persists, restart your computer. [APP_NAME] appears to have frozen or crashed on the previous run. Would you like to send a crash report? </string> + <string name="MBFreezeDetected"> + [APP_NAME] appears to have frozen. If this issue occurs regularly, please contact support at https://support.secondlife.com. + </string> <string name="MBAlert">Notification</string> <string name="MBNoDirectX"> [APP_NAME] is unable to detect DirectX 9.0b or greater. |
