From fe1537104737d21a2180ba34ec77d6652356dd92 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Tue, 13 Nov 2012 17:55:52 -0600 Subject: [PATCH] Update to LLTombstone/LLHandle/LLRootHandle/LLHandleProvider. --- indra/llui/llfloater.cpp | 6 +- indra/llui/llfloater.h | 3 +- indra/llui/llhandle.h | 125 ++++++++++++++++++++-------- indra/llui/llpanel.cpp | 1 - indra/llui/llpanel.h | 3 +- indra/llui/llview.h | 7 +- indra/newview/llfasttimerview.cpp | 2 +- indra/newview/llinventorybridge.cpp | 42 +++++++--- indra/newview/llinventorybridge.h | 2 +- indra/newview/llinventorypanel.h | 2 + indra/newview/llpanelmediahud.cpp | 2 - indra/newview/llpanelmediahud.h | 4 +- 12 files changed, 130 insertions(+), 69 deletions(-) diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 114cabc0c..25370f739 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -148,7 +148,6 @@ LLFloater::LLFloater() : mResizeHandle[i] = NULL; } mDragHandle = NULL; - mHandle.bind(this); mNotificationContext = new LLFloaterNotificationContext(getHandle()); } @@ -222,7 +221,6 @@ void LLFloater::initFloater(const std::string& title, BOOL resizable, S32 min_width, S32 min_height, BOOL drag_on_left, BOOL minimizable, BOOL close_btn) { - mHandle.bind(this); mNotificationContext = new LLFloaterNotificationContext(getHandle()); // Init function can be called more than once, so clear out old data. @@ -422,7 +420,7 @@ void LLFloater::initFloater(const std::string& title, setVisible(FALSE); // add self to handle->floater map - sFloaterMap[mHandle] = this; + sFloaterMap[getHandle()] = this; if (!getParent()) { @@ -483,7 +481,7 @@ LLFloater::~LLFloater() // correct, non-minimized positions. setMinimized( FALSE ); - sFloaterMap.erase(mHandle); + sFloaterMap.erase(getHandle()); delete mDragHandle; for (S32 i = 0; i < 4; i++) diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index e710fa6dc..1cfb4635a 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -227,7 +227,7 @@ public: void clearSnapTarget() { mSnappedTo.markDead(); } LLHandle getSnapTarget() const { return mSnappedTo; } - LLHandle getHandle() const { return mHandle; } + LLHandle getHandle() const { return getDerivedHandle(); } // Return a closeable floater, if any, given the current focus. static LLFloater* getClosableFloaterFromFocus(); @@ -331,7 +331,6 @@ private: S32 mPreviousMinimizedLeft; LLFloaterNotificationContext* mNotificationContext; - LLRootHandle mHandle; }; ///////////////////////////////////////////////////////////// diff --git a/indra/llui/llhandle.h b/indra/llui/llhandle.h index 8c000eee4..6af5e198d 100644 --- a/indra/llui/llhandle.h +++ b/indra/llui/llhandle.h @@ -28,38 +28,67 @@ #define LLHANDLE_H #include "llpointer.h" +#include +#include -template +/** + * Helper object for LLHandle. Don't instantiate these directly, used + * exclusively by LLHandle. + */ class LLTombStone : public LLRefCount { public: - LLTombStone(T* target = NULL) : mTarget(target) {} + LLTombStone(void* target = NULL) : mTarget(target) {} - void setTarget(T* target) { mTarget = target; } - T* getTarget() const { return mTarget; } + void setTarget(void* target) { mTarget = target; } + void* getTarget() const { return mTarget; } private: - T* mTarget; + mutable void* mTarget; }; -// LLHandles are used to refer to objects whose lifetime you do not control or influence. -// Calling get() on a handle will return a pointer to the referenced object or NULL, -// if the object no longer exists. Note that during the lifetime of the returned pointer, -// you are assuming that the object will not be deleted by any action you perform, -// or any other thread, as normal when using pointers, so avoid using that pointer outside of -// the local code block. -// -// https://wiki.lindenlab.com/mediawiki/index.php?title=LLHandle&oldid=79669 - +/** + * LLHandles are used to refer to objects whose lifetime you do not control or influence. + * Calling get() on a handle will return a pointer to the referenced object or NULL, + * if the object no longer exists. Note that during the lifetime of the returned pointer, + * you are assuming that the object will not be deleted by any action you perform, + * or any other thread, as normal when using pointers, so avoid using that pointer outside of + * the local code block. + * + * https://wiki.lindenlab.com/mediawiki/index.php?title=LLHandle&oldid=79669 + * + * The implementation is like some "weak pointer" implementations. When we + * can't control the lifespan of the referenced object of interest, we can + * still instantiate a proxy object whose lifespan we DO control, and store in + * the proxy object a dumb pointer to the actual target. Then we just have to + * ensure that on destruction of the target object, the proxy's dumb pointer + * is set NULL. + * + * LLTombStone is our proxy object. LLHandle contains an LLPointer to the + * LLTombStone, so every copy of an LLHandle increments the LLTombStone's ref + * count as usual. + * + * One copy of the LLHandle, specifically the LLRootHandle, must be stored in + * the referenced object. Destroying the LLRootHandle is what NULLs the + * proxy's target pointer. + * + * Minor optimization: we want LLHandle's mTombStone to always be a valid + * LLPointer, saving some conditionals in dereferencing. That's the + * getDefaultTombStone() mechanism. The default LLTombStone object's target + * pointer is always NULL, so it's semantically identical to allowing + * mTombStone to be invalid. + */ template class LLHandle { + template friend class LLHandle; + template friend class LLHandleProvider; public: LLHandle() : mTombStone(getDefaultTombStone()) {} - const LLHandle& operator =(const LLHandle& other) - { - mTombStone = other.mTombStone; - return *this; - } + + template + LLHandle(const LLHandle& other, typename boost::enable_if< typename boost::is_convertible >::type* dummy = 0) + : mTombStone(other.mTombStone) + {} bool isDead() const { @@ -73,7 +102,7 @@ public: T* get() const { - return mTombStone->getTarget(); + return reinterpret_cast(mTombStone->getTarget()); } friend bool operator== (const LLHandle& lhs, const LLHandle& rhs) @@ -94,37 +123,49 @@ public: } protected: - LLPointer > mTombStone; + LLPointer mTombStone; private: - static LLPointer >& getDefaultTombStone() + typedef T* pointer_t; + static LLPointer& getDefaultTombStone() { - static LLPointer > sDefaultTombStone = new LLTombStone; + static LLPointer sDefaultTombStone = new LLTombStone; return sDefaultTombStone; } }; +/** + * LLRootHandle isa LLHandle which must be stored in the referenced object. + * You can either store it directly and explicitly bind(this), or derive from + * LLHandleProvider (q.v.) which automates that for you. The essential point + * is that destroying the LLRootHandle (as a consequence of destroying the + * referenced object) calls unbind(), setting the LLTombStone's target pointer + * NULL. + */ template class LLRootHandle : public LLHandle { public: + typedef LLRootHandle self_t; + typedef LLHandle base_t; + LLRootHandle(T* object) { bind(object); } LLRootHandle() {}; ~LLRootHandle() { unbind(); } - // this is redundant, since a LLRootHandle *is* an LLHandle - LLHandle getHandle() { return LLHandle(*this); } + // this is redundant, since an LLRootHandle *is* an LLHandle + //LLHandle getHandle() { return LLHandle(*this); } void bind(T* object) { // unbind existing tombstone if (LLHandle::mTombStone.notNull()) { - if (LLHandle::mTombStone->getTarget() == object) return; + if (LLHandle::mTombStone->getTarget() == (void*)object) return; LLHandle::mTombStone->setTarget(NULL); } // tombstone reference counted, so no paired delete - LLHandle::mTombStone = new LLTombStone(object); + LLHandle::mTombStone = new LLTombStone((void*)object); } void unbind() @@ -137,11 +178,22 @@ private: LLRootHandle(const LLRootHandle& other) {}; }; -// Use this as a mixin for simple classes that need handles and when you don't -// want handles at multiple points of the inheritance hierarchy +/** + * Use this as a mixin for simple classes that need handles and when you don't + * want handles at multiple points of the inheritance hierarchy + */ template class LLHandleProvider { +public: + LLHandle getHandle() const + { + // perform lazy binding to avoid small tombstone allocations for handle + // providers whose handles are never referenced + mHandle.bind(static_cast(const_cast* >(this))); + return mHandle; + } + protected: typedef LLHandle handle_type_t; LLHandleProvider() @@ -149,16 +201,17 @@ protected: // provided here to enforce T deriving from LLHandleProvider } - LLHandle getHandle() - { - // perform lazy binding to avoid small tombstone allocations for handle - // providers whose handles are never referenced - mHandle.bind(static_cast(this)); - return mHandle; + template + LLHandle getDerivedHandle(typename boost::enable_if< typename boost::is_convertible >::type* dummy = 0) const + { + LLHandle downcast_handle; + downcast_handle.mTombStone = getHandle().mTombStone; + return downcast_handle; } + private: - LLRootHandle mHandle; + mutable LLRootHandle mHandle; }; #endif diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index 136dcf524..dc89e9a4f 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -80,7 +80,6 @@ void LLPanel::init() mDefaultBtn = NULL; setIsChrome(FALSE); //is this a decorator to a live window or a form? - mPanelHandle.bind(this); setTabStop(FALSE); mVisibleSignal = NULL; } diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h index ad721cbf5..dbf17aec6 100644 --- a/indra/llui/llpanel.h +++ b/indra/llui/llpanel.h @@ -136,7 +136,7 @@ public: void setCtrlsEnabled(BOOL b); - LLHandle getHandle() const { return mPanelHandle; } + LLHandle getHandle() const { return getDerivedHandle(); } const LLCallbackMap::map_t& getFactoryMap() const { return mFactoryMap; } @@ -246,7 +246,6 @@ private: LLViewBorder* mBorder; LLButton* mDefaultBtn; std::string mLabel; - LLRootHandle mPanelHandle; typedef std::map ui_string_map_t; ui_string_map_t mUIStrings; diff --git a/indra/llui/llview.h b/indra/llui/llview.h index ee2ad2d3e..c2dc57384 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -132,8 +132,8 @@ public: class LLView : public LLMouseHandler, // handles mouse events public LLFocusableElement, // handles keyboard events - public LLMortician // lazy deletion - //public LLHandleProvider // passes out weak references to self + public LLMortician, // lazy deletion + public LLHandleProvider // passes out weak references to self { public: struct Follows : public LLInitParam::ChoiceBlock @@ -344,8 +344,6 @@ public: void popVisible() { setVisible(mLastVisible); } BOOL getLastVisible() const { return mLastVisible; } - LLHandle getHandle() { mHandle.bind(this); return mHandle; } - U32 getFollows() const { return mReshapeFlags; } BOOL followsLeft() const { return mReshapeFlags & FOLLOWS_LEFT; } BOOL followsRight() const { return mReshapeFlags & FOLLOWS_RIGHT; } @@ -678,7 +676,6 @@ private: BOOL mIsFocusRoot; BOOL mUseBoundingRect; // hit test against bounding rectangle that includes all child elements - LLRootHandle mHandle; BOOL mLastVisible; S32 mNextInsertionOrdinal; diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index eeb53a98d..46d0d0740 100644 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -971,7 +971,7 @@ void LLFastTimerView::draw() gGL.color4f(col[0], col[1], col[2], alpha); gGL.begin(LLRender::TRIANGLE_STRIP); for (U32 j = llmax(0, LLFastTimer::NamedTimer::HISTORY_NUM - LLFastTimer::getLastFrameIndex()); - j < LLFastTimer::NamedTimer::HISTORY_NUM; + j < (U32)LLFastTimer::NamedTimer::HISTORY_NUM; j++) { U64 ticks = idp->getHistoricalCount(j); diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index e2f6144fb..2e09a7339 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -263,7 +263,7 @@ LLInvFVBridge::LLInvFVBridge(LLInventoryPanel* inventory, mInvType(LLInventoryType::IT_NONE), mIsLink(FALSE) { - mInventoryPanel = inventory->getHandle(); + mInventoryPanel = inventory->getInventoryPanelHandle(); const LLInventoryObject* obj = getInventoryObject(); mIsLink = obj && obj->getIsLinkType(); } @@ -973,7 +973,7 @@ LLInventoryObject* LLInvFVBridge::getInventoryObject() const LLInventoryModel* LLInvFVBridge::getInventoryModel() const { - LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); + LLInventoryPanel* panel = mInventoryPanel.get(); return panel ? panel->getModel() : NULL; } @@ -1937,7 +1937,7 @@ BOOL LLFolderBridge::isItemRemovable() const return FALSE; } - LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); + LLInventoryPanel* panel = mInventoryPanel.get(); LLFolderViewFolder* folderp = dynamic_cast(panel ? panel->getRootFolder()->getItemByID(mUUID) : NULL); if (folderp) { @@ -3200,7 +3200,7 @@ void LLFolderBridge::buildContextMenuBaseOptions(U32 flags) // Not sure what the right thing is to do here. if (!isCOFFolder() && cat && (cat->getPreferredType() != LLFolderType::FT_OUTFIT)) { - LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); + LLInventoryPanel* panel = mInventoryPanel.get(); if(panel && !panel->getFilterWorn()) if (!isInboxFolder() && !isOutboxFolder()) // don't allow creation in inbox or outbox { @@ -3481,7 +3481,7 @@ void LLFolderBridge::createNewCategory(void* user_data) { LLFolderBridge* bridge = (LLFolderBridge*)user_data; if(!bridge) return; - LLInventoryPanel* panel = dynamic_cast(bridge->mInventoryPanel.get()); + LLInventoryPanel* panel = bridge->mInventoryPanel.get(); if (!panel) return; LLInventoryModel* model = panel->getModel(); if(!model) return; @@ -3675,7 +3675,7 @@ void LLFolderBridge::dropToFavorites(LLInventoryItem* inv_item) // use callback to rearrange favorite landmarks after adding // to have new one placed before target (on which it was dropped). See EXT-4312. LLPointer cb = new AddFavoriteLandmarkCallback(); - LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); + LLInventoryPanel* panel = mInventoryPanel.get(); LLFolderViewItem* drag_over_item = panel ? panel->getRootFolder()->getDraggingOverItem() : NULL; if (drag_over_item && drag_over_item->getListener()) { @@ -3724,6 +3724,9 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, if(!isAgentInventory()) return FALSE; // cannot drag into library if (!isAgentAvatarValid()) return FALSE; + LLInventoryPanel* destination_panel = mInventoryPanel.get(); + if (!destination_panel) return false; + const LLUUID ¤t_outfit_id = model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, false); const LLUUID &favorites_id = model->findCategoryUUIDForType(LLFolderType::FT_FAVORITE, false); const LLUUID &landmarks_id = model->findCategoryUUIDForType(LLFolderType::FT_LANDMARK, false); @@ -3855,6 +3858,15 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, } } + LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE); + + // Check whether the item being dragged from active inventory panel + if (accept && active_panel) + { + LLFolderView* active_folder_view = active_panel->getRootFolder(); + if (!active_folder_view) return false; + } + if(accept && drop) { if (inv_item->getType() == LLAssetType::AT_GESTURE @@ -3864,14 +3876,9 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, } // If an item is being dragged between windows, unselect everything in the active window // so that we don't follow the selection to its new location (which is very annoying). - LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE); - if (active_panel) + if (active_panel && (destination_panel != active_panel)) { - LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); - if (active_panel && (panel != active_panel)) - { active_panel->unSelectAll(); - } } // FAVORITES folder @@ -4034,6 +4041,15 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, accept = can_move_to_landmarks(inv_item); } + LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE); + + // Check whether the item being dragged from the library + if (accept && active_panel) + { + LLFolderView* active_folder_view = active_panel->getRootFolder(); + if (!active_folder_view) return false; + } + if (accept && drop) { // FAVORITES folder @@ -4436,7 +4452,7 @@ LLCallingCardBridge::~LLCallingCardBridge() void LLCallingCardBridge::refreshFolderViewItem() { - LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); + LLInventoryPanel* panel = mInventoryPanel.get(); LLFolderViewItem* itemp = panel ? panel->getRootFolder()->getItemByID(mUUID) : NULL; if (itemp) { diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index c3c883a42..f2b5c4215 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -160,7 +160,7 @@ protected: BOOL restamp); void removeBatchNoCheck(LLDynamicArray& batch); protected: - LLHandle mInventoryPanel; + LLHandle mInventoryPanel; LLFolderView* mRoot; const LLUUID mUUID; // item id LLInventoryType::EType mInvType; diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h index 4a2953f7f..f7d58b79a 100644 --- a/indra/newview/llinventorypanel.h +++ b/indra/newview/llinventorypanel.h @@ -129,6 +129,8 @@ public: LLScrollableContainerView* getScrollableContainer() { return mScroller; } void onSelectionChange(const std::deque &items, BOOL user_action); + + LLHandle getInventoryPanelHandle() const { return getDerivedHandle(); } // DEBUG ONLY: static void dumpSelectionInformation(void* user_data); diff --git a/indra/newview/llpanelmediahud.cpp b/indra/newview/llpanelmediahud.cpp index 2fcee26c6..27d1473d6 100644 --- a/indra/newview/llpanelmediahud.cpp +++ b/indra/newview/llpanelmediahud.cpp @@ -78,8 +78,6 @@ LLPanelMediaHUD::LLPanelMediaHUD(viewer_media_t media_impl) mFadeTimer.stop(); mCurrentZoom = ZOOM_NONE; mScrollState = SCROLL_NONE; - - mPanelHandle.bind(this); } LLPanelMediaHUD::~LLPanelMediaHUD() { diff --git a/indra/newview/llpanelmediahud.h b/indra/newview/llpanelmediahud.h index 81d40591e..1d1f5e1be 100644 --- a/indra/newview/llpanelmediahud.h +++ b/indra/newview/llpanelmediahud.h @@ -55,7 +55,8 @@ public: void nextZoomLevel(); void resetZoomLevel() { mCurrentZoom = ZOOM_NONE; } - LLHandle getHandle() const { return mPanelHandle; } + LLHandle getHandle() const { return getDerivedHandle(); } + void setMediaImpl(viewer_media_t media_impl) { mMediaImpl = media_impl; } @@ -105,7 +106,6 @@ private: F32 mMouseInactiveTime; F32 mControlFadeTime; viewer_media_t mMediaImpl; - LLRootHandle mPanelHandle; }; #endif // LL_PANELMEDIAHUD_H