diff -r 7dbd8eaefaec -r 526d86e69101 indra/newview/llappviewer.h --- a/indra/newview/llappviewer.h Wed Aug 17 23:07:14 2011 -0400 +++ b/indra/newview/llappviewer.h Fri Aug 26 00:19:33 2011 +0300 @@ -164,6 +164,8 @@ public: login_completed_signal_t mOnLoginCompleted; boost::signals2::connection setOnLoginCompletedCallback( const login_completed_signal_t::slot_type& cb ) { return mOnLoginCompleted.connect(cb); } + void addOnIdleCallback(const boost::function& cb); // add a callback to fire (once) when idle + void purgeCache(); // Clear the local cache. // mute/unmute the system's master audio diff -r 7dbd8eaefaec -r 526d86e69101 indra/newview/llappviewer.cpp --- a/indra/newview/llappviewer.cpp Wed Aug 17 23:07:14 2011 -0400 +++ b/indra/newview/llappviewer.cpp Fri Aug 26 00:19:33 2011 +0300 @@ -321,6 +321,41 @@ static std::string gLaunchFileOnQuit; // Used on Win32 for other apps to identify our window (eg, win_setup) const char* const VIEWER_WINDOW_CLASSNAME = "Second Life"; +//-- LLDeferredTaskList ------------------------------------------------------ + +/** + * A list of deferred tasks. + * + * We sometimes need to defer execution of some code until the viewer gets idle, + * e.g. removing an inventory item from within notifyObservers() may not work out. + * + * Tasks added to this list will be executed in the next LLAppViewer::idle() iteration. + * All tasks are executed only once. + */ +class LLDeferredTaskList: public LLSingleton +{ + LOG_CLASS(LLDeferredTaskList); + + friend class LLAppViewer; + typedef boost::signals2::signal signal_t; + + void addTask(const signal_t::slot_type& cb) + { + mSignal.connect(cb); + } + + void run() + { + if (!mSignal.empty()) + { + mSignal(); + mSignal.disconnect_all_slots(); + } + } + + signal_t mSignal; +}; + //---------------------------------------------------------------------------- // List of entries from strings.xml to always replace @@ -3820,6 +3855,11 @@ bool LLAppViewer::initCache() } } +void LLAppViewer::addOnIdleCallback(const boost::function& cb) +{ + LLDeferredTaskList::instance().addTask(cb); +} + void LLAppViewer::purgeCache() { LL_INFOS("AppCache") << "Purging Cache and Texture Cache..." << LL_ENDL; @@ -4413,6 +4453,9 @@ void LLAppViewer::idle() gAudiop->idle(max_audio_decode_time); } } + + // Execute deferred tasks. + LLDeferredTaskList::instance().run(); // Handle shutdown process, for example, // wait for floaters to close, send quit message, diff -r 7dbd8eaefaec -r 526d86e69101 indra/newview/llviewermessage.h --- a/indra/newview/llviewermessage.h Wed Aug 17 23:07:14 2011 -0400 +++ b/indra/newview/llviewermessage.h Fri Aug 26 00:19:33 2011 +0300 @@ -57,7 +57,6 @@ enum InventoryOfferResponse IOR_ACCEPT, IOR_DECLINE, IOR_MUTE, - IOR_BUSY, IOR_SHOW }; diff -r 7dbd8eaefaec -r 526d86e69101 indra/newview/llviewermessage.cpp --- a/indra/newview/llviewermessage.cpp Wed Aug 17 23:07:14 2011 -0400 +++ b/indra/newview/llviewermessage.cpp Fri Aug 26 00:19:33 2011 +0300 @@ -1049,48 +1049,26 @@ void start_new_inventory_observer() class LLDiscardAgentOffer : public LLInventoryFetchItemsObserver { LOG_CLASS(LLDiscardAgentOffer); + public: LLDiscardAgentOffer(const LLUUID& folder_id, const LLUUID& object_id) : LLInventoryFetchItemsObserver(object_id), mFolderID(folder_id), mObjectID(object_id) {} - virtual ~LLDiscardAgentOffer() {} + virtual void done() { LL_DEBUGS("Messaging") << "LLDiscardAgentOffer::done()" << LL_ENDL; - const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); - bool notify = false; - if(trash_id.notNull() && mObjectID.notNull()) - { - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(mFolderID, -1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(trash_id, 1); - update.push_back(new_folder); - gInventory.accountForUpdate(update); - gInventory.moveObject(mObjectID, trash_id); - LLInventoryObject* obj = gInventory.getObject(mObjectID); - if(obj) - { - // no need to restamp since this is already a freshly - // stamped item. - obj->updateParentOnServer(FALSE); - notify = true; - } - } - else - { - LL_WARNS("Messaging") << "DiscardAgentOffer unable to find: " - << (trash_id.isNull() ? "trash " : "") - << (mObjectID.isNull() ? "object" : "") << LL_ENDL; - } + + // We're invoked from LLInventoryModel::notifyObservers(). + // If we now try to remove the inventory item, it will cause a nested + // notifyObservers() call, which won't work. + // So defer moving the item to trash until viewer gets idle (in a moment). + LLAppViewer::instance()->addOnIdleCallback(boost::bind(&LLInventoryModel::removeItem, &gInventory, mObjectID)); gInventory.removeObserver(this); - if(notify) - { - gInventory.notifyObservers(); - } delete this; } + protected: LLUUID mFolderID; LLUUID mObjectID; @@ -1495,7 +1473,7 @@ bool LLOfferInfo::inventory_offer_callba LLChat chat; std::string log_message; S32 button = LLNotificationsUtil::getSelectedOption(notification, response); - + LLInventoryObserver* opener = NULL; LLViewerInventoryCategory* catp = NULL; catp = (LLViewerInventoryCategory*)gInventory.getCategory(mObjectID); @@ -1527,7 +1505,7 @@ bool LLOfferInfo::inventory_offer_callba // TODO: when task inventory offers can also be handled the new way, migrate the code that sets these strings here: from_string = chatHistory_string = mFromName; - bool busy=FALSE; + bool busy = gAgent.getBusy(); switch(button) { @@ -1586,9 +1564,6 @@ bool LLOfferInfo::inventory_offer_callba } break; - case IOR_BUSY: - //Busy falls through to decline. Says to make busy message. - busy=TRUE; case IOR_MUTE: // MUTE falls through to decline case IOR_DECLINE: @@ -1734,7 +1709,7 @@ bool LLOfferInfo::inventory_task_offer_c from_string = chatHistory_string = mFromName; } - bool busy=FALSE; + bool busy = gAgent.getBusy(); switch(button) { @@ -1780,9 +1755,6 @@ bool LLOfferInfo::inventory_task_offer_c } // end switch (mIM) break; - case IOR_BUSY: - //Busy falls through to decline. Says to make busy message. - busy=TRUE; case IOR_MUTE: // MUTE falls through to decline case IOR_DECLINE: @@ -2667,7 +2639,7 @@ void process_improved_im(LLMessageSystem { // Until throttling is implemented, busy mode should reject inventory instead of silently // accepting it. SEE SL-39554 - info->forceResponse(IOR_BUSY); + info->forceResponse(IOR_DECLINE); } else {