From 4549256c2b685782587f2ccad6a105c0392492c7 Mon Sep 17 00:00:00 2001 From: janekptacijarabaci Date: Fri, 20 Apr 2018 22:54:26 +0200 Subject: moebius#56: Fix: DataTransfer - Pasting image from clipboard fails in some cases https://github.com/MoonchildProductions/moebius/pull/56 --- widget/windows/nsClipboard.cpp | 2 +- widget/windows/nsDataObj.cpp | 99 ++++++++++++++++++++++++++++++++++-------- widget/windows/nsDataObj.h | 1 - 3 files changed, 81 insertions(+), 21 deletions(-) (limited to 'widget') diff --git a/widget/windows/nsClipboard.cpp b/widget/windows/nsClipboard.cpp index 1afee3496..0db1dd342 100644 --- a/widget/windows/nsClipboard.cpp +++ b/widget/windows/nsClipboard.cpp @@ -65,7 +65,7 @@ nsClipboard::nsClipboard() : nsBaseClipboard() nsCOMPtr observerService = do_GetService("@mozilla.org/observer-service;1"); if (observerService) - observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE); + observerService->AddObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, PR_FALSE); } //------------------------------------------------------------------------- diff --git a/widget/windows/nsDataObj.cpp b/widget/windows/nsDataObj.cpp index 02ec3b2fe..977a87c08 100644 --- a/widget/windows/nsDataObj.cpp +++ b/widget/windows/nsDataObj.cpp @@ -443,6 +443,82 @@ STDMETHODIMP_(ULONG) nsDataObj::AddRef() return m_cRef; } +namespace { +class RemoveTempFileHelper : public nsIObserver +{ +public: + explicit RemoveTempFileHelper(nsIFile* aTempFile) + : mTempFile(aTempFile) + { + MOZ_ASSERT(mTempFile); + } + + // The attach method is seperate from the constructor as we may be addref-ing + // ourself, and we want to be sure someone has a strong reference to us. + void Attach() + { + // We need to listen to both the xpcom shutdown message and our timer, and + // fire when the first of either of these two messages is received. + nsresult rv; + mTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + mTimer->Init(this, 500, nsITimer::TYPE_ONE_SHOT); + + nsCOMPtr observerService = + do_GetService("@mozilla.org/observer-service;1"); + if (NS_WARN_IF(!observerService)) { + mTimer->Cancel(); + mTimer = nullptr; + return; + } + observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); + } + + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER + +private: + ~RemoveTempFileHelper() + { + if (mTempFile) { + mTempFile->Remove(false); + } + } + + nsCOMPtr mTempFile; + nsCOMPtr mTimer; +}; + +NS_IMPL_ISUPPORTS(RemoveTempFileHelper, nsIObserver); + +NS_IMETHODIMP +RemoveTempFileHelper::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) +{ + // Let's be careful and make sure that we don't die immediately + RefPtr grip = this; + + // Make sure that we aren't called again by destroying references to ourself. + nsCOMPtr observerService = + do_GetService("@mozilla.org/observer-service;1"); + if (observerService) { + observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); + } + + if (mTimer) { + mTimer->Cancel(); + mTimer = nullptr; + } + + // Remove the tempfile + if (mTempFile) { + mTempFile->Remove(false); + mTempFile = nullptr; + } + return NS_OK; +} +} // namespace //----------------------------------------------------- STDMETHODIMP_(ULONG) nsDataObj::Release() @@ -456,17 +532,12 @@ STDMETHODIMP_(ULONG) nsDataObj::Release() // We have released our last ref on this object and need to delete the // temp file. External app acting as drop target may still need to open the // temp file. Addref a timer so it can delay deleting file and destroying - // this object. Delete file anyway and destroy this obj if there's a problem. + // this object. if (mCachedTempFile) { - nsresult rv; - mTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv); - if (NS_SUCCEEDED(rv)) { - mTimer->InitWithFuncCallback(nsDataObj::RemoveTempFile, this, - 500, nsITimer::TYPE_ONE_SHOT); - return AddRef(); - } - mCachedTempFile->Remove(false); + RefPtr helper = + new RemoveTempFileHelper(mCachedTempFile); mCachedTempFile = nullptr; + helper->Attach(); } delete this; @@ -2153,13 +2224,3 @@ HRESULT nsDataObj::GetFileContents_IStream(FORMATETC& aFE, STGMEDIUM& aSTG) return S_OK; } - -void nsDataObj::RemoveTempFile(nsITimer* aTimer, void* aClosure) -{ - nsDataObj *timedDataObj = static_cast(aClosure); - if (timedDataObj->mCachedTempFile) { - timedDataObj->mCachedTempFile->Remove(false); - timedDataObj->mCachedTempFile = nullptr; - } - timedDataObj->Release(); -} diff --git a/widget/windows/nsDataObj.h b/widget/windows/nsDataObj.h index 2d7fb75ee..61f209e85 100644 --- a/widget/windows/nsDataObj.h +++ b/widget/windows/nsDataObj.h @@ -289,7 +289,6 @@ protected: bool LookupArbitraryFormat(FORMATETC *aFormat, LPDATAENTRY *aDataEntry, BOOL aAddorUpdate); bool CopyMediumData(STGMEDIUM *aMediumDst, STGMEDIUM *aMediumSrc, LPFORMATETC aFormat, BOOL aSetData); - static void RemoveTempFile(nsITimer* aTimer, void* aClosure); }; -- cgit v1.2.3