From 6d8c0d0d57ba28ae00bcdbd3617e54a63507e508 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Fri, 16 Jan 2026 04:49:17 +0200 Subject: #5276 Freeze when bulk editing outfits Schedule refreshOutfit into idle loop instead of doing lots of updates at once. --- indra/newview/lloutfitgallery.cpp | 19 ++++++++++++++++++- indra/newview/lloutfitgallery.h | 2 ++ indra/newview/lloutfitslist.cpp | 17 +++++++++++++++++ indra/newview/lloutfitslist.h | 13 +++++++++++++ 4 files changed, 50 insertions(+), 1 deletion(-) diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index 8589afae06..852f2dab21 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -850,7 +850,12 @@ void LLOutfitGallery::updateAddedCategory(LLUUID cat_id) // Start observing changes in "My Outfits" category. mCategoriesObserver->addCategory(cat_id, - boost::bind(&LLOutfitGallery::refreshOutfit, this, cat_id), true); + [this, cat_id]() + { + mPendingOutfitRefreshes.insert(cat_id); + startIdleLoop(cat_id); + }, + true); outfit_category->fetch(); refreshOutfit(cat_id); @@ -901,6 +906,18 @@ void LLOutfitGallery::updateChangedCategoryName(LLViewerInventoryCategory *cat, } } +bool LLOutfitGallery::updateOneOutfit() +{ + if (mPendingOutfitRefreshes.empty()) + return false; + + auto it = mPendingOutfitRefreshes.begin(); + LLUUID outfit_id = *it; + mPendingOutfitRefreshes.erase(it); + refreshOutfit(outfit_id); + return true; +} + void LLOutfitGallery::onOutfitRightClick(LLUICtrl* ctrl, S32 x, S32 y, const LLUUID& cat_id) { if (mOutfitMenu && cat_id.notNull()) diff --git a/indra/newview/lloutfitgallery.h b/indra/newview/lloutfitgallery.h index 5801a32a39..183b6ea9d5 100644 --- a/indra/newview/lloutfitgallery.h +++ b/indra/newview/lloutfitgallery.h @@ -98,6 +98,7 @@ public: /*virtual*/ void updateAddedCategory(LLUUID cat_id); /*virtual*/ void updateRemovedCategory(LLUUID cat_id); /*virtual*/ void updateChangedCategoryName(LLViewerInventoryCategory *cat, std::string name); + /*virtual*/ bool updateOneOutfit(); // bulk processing, scheduled by observer when updates are needed /*virtual*/ bool hasItemSelected(); /*virtual*/ bool canWearSelected(); @@ -190,6 +191,7 @@ private: typedef item_num_map_t::value_type item_numb_map_value_t; item_num_map_t mItemIndexMap; std::map mIndexToItemMap; + std::set mPendingOutfitRefreshes; LLInventoryCategoriesObserver* mOutfitsObserver; diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 32831fcd9b..7db79c7010 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -1055,6 +1055,15 @@ void LLOutfitListBase::refreshList(const LLUUID& category_id) } } +void LLOutfitListBase::startIdleLoop(const LLUUID cat_id) +{ + if (mRefreshListState.CategoryUUID.isNull()) + { + mRefreshListState.CategoryUUID = cat_id; + gIdleCallbacks.addFunction(onIdle, this); + } +} + // static void LLOutfitListBase::onIdle(void* userdata) { @@ -1129,6 +1138,14 @@ void LLOutfitListBase::onIdleRefreshList() return; } + // Let derived classes process their own updates. + while (updateOneOutfit()) + { + curent_time = LLTimer::getTotalSeconds(); + if (curent_time >= end_time) + return; + } + sortOutfits(); highlightBaseOutfit(); diff --git a/indra/newview/lloutfitslist.h b/indra/newview/lloutfitslist.h index bcf7e45696..408ff07116 100644 --- a/indra/newview/lloutfitslist.h +++ b/indra/newview/lloutfitslist.h @@ -95,6 +95,17 @@ public: virtual void updateAddedCategory(LLUUID cat_id) = 0; virtual void updateRemovedCategory(LLUUID cat_id) = 0; virtual void updateChangedCategoryName(LLViewerInventoryCategory *cat, std::string name) = 0; + + /* + * Optional hook for derived classes to perform additional processing. + * This is called by the outfit list update logic after the core + * bookkeeping for an outfit has been handled. + * + * @return true if update processing should continue, + * false if no additional work is required. + * The base implementation returns false. + */ + virtual bool updateOneOutfit() { return false; }; virtual void sortOutfits(); void removeSelected(); @@ -138,6 +149,7 @@ protected: bool isOutfitFolder(LLViewerInventoryCategory* cat) const; + void startIdleLoop(const LLUUID cat_id); static void onIdle(void* userdata); void onIdleRefreshList(); @@ -150,6 +162,7 @@ protected: uuid_vec_t::const_iterator RemovedIterator; } mRefreshListState; std::set mChangedItems; + std::set mPendingOutfitRefreshes; bool mIsInitialized; LLInventoryCategoriesObserver* mCategoriesObserver; -- cgit v1.3