Bug 494989 - Windows drag and drop does not use temporary file when needed--fixes dragging image to apps that can handle images. r=roc, r=jmathies.

This commit is contained in:
Phil Lacy 2009-12-17 22:06:19 -06:00
Родитель f8ae6ca13f
Коммит 8170eb63e3
3 изменённых файлов: 118 добавлений и 124 удалений

Просмотреть файл

@ -63,6 +63,7 @@
#include "nscore.h"
#include "prtypes.h"
#include "nsDirectoryServiceDefs.h"
#include "nsITimer.h"
// XXX Duped from profile/src/nsProfile.cpp.
#include <stdlib.h>
@ -448,6 +449,22 @@ STDMETHODIMP_(ULONG) nsDataObj::Release()
if (0 != m_cRef)
return m_cRef;
// 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.
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(PR_FALSE);
mCachedTempFile = NULL;
}
delete this;
return 0;
@ -622,15 +639,6 @@ IUnknown* nsDataObj::GetCanonicalIUnknown(IUnknown *punk)
STDMETHODIMP nsDataObj::SetData(LPFORMATETC pFE, LPSTGMEDIUM pSTM, BOOL fRelease)
{
PRNTDEBUG("nsDataObj::SetData\n");
static CLIPFORMAT PerformedDropEffect = ::RegisterClipboardFormat( CFSTR_PERFORMEDDROPEFFECT );
if (pFE && pFE->cfFormat == PerformedDropEffect) {
// The drop operation has completed. Delete the temp file if it exists.
if (mCachedTempFile) {
mCachedTempFile->Remove(PR_FALSE);
mCachedTempFile = NULL;
}
}
// Store arbitrary system formats
LPDATAENTRY pde;
HRESULT hres = FindFORMATETC(pFE, &pde, TRUE); // add
@ -1355,8 +1363,6 @@ HRESULT nsDataObj::GetText(const nsACString & aDataFlavor, FORMATETC& aFE, STGME
//-----------------------------------------------------
HRESULT nsDataObj::GetFile(FORMATETC& aFE, STGMEDIUM& aSTG)
{
HRESULT res = S_OK;
// We do not support 'application/x-moz-file-promise' since CF_HDROP does not
// allow for delayed rendering of content. We'll need to write the content out emmediately
// and return the path to it. Confirm we have support for 'application/x-moz-nativeimage',
@ -1449,6 +1455,7 @@ HRESULT nsDataObj::DropFile(FORMATETC& aFE, STGMEDIUM& aSTG)
HRESULT nsDataObj::DropImage(FORMATETC& aFE, STGMEDIUM& aSTG)
{
nsresult rv;
if (!mCachedTempFile) {
PRUint32 len = 0;
nsCOMPtr<nsISupports> genericDataWrapper;
@ -1482,19 +1489,16 @@ HRESULT nsDataObj::DropImage(FORMATETC& aFE, STGMEDIUM& aSTG)
return E_FAIL;
}
if (mCachedTempFile) {
mCachedTempFile->Remove(PR_FALSE);
mCachedTempFile = NULL;
}
// Save the bitmap to a temporary location.
nsCOMPtr<nsIFile> dropFile;
rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(dropFile));
if (!dropFile)
if (!dropFile) {
GlobalFree(bits);
return E_FAIL;
}
// Filename must be random so as not to confuse apps like Photshop which handle
// multiple drags into a single window.
// Filename must be random so as not to confuse apps like
// Photoshop which handle multiple drags into a single window.
char buf[13];
nsCString filename;
MakeRandomString(buf, 8);
@ -1507,7 +1511,9 @@ HRESULT nsDataObj::DropImage(FORMATETC& aFE, STGMEDIUM& aSTG)
return E_FAIL;
}
// Cache the temp file so we can delete it later.
// Cache the temp file so we can delete it later and so
// it doesn't get recreated over and over on multiple calls
// which does occur from windows shell.
dropFile->Clone(getter_AddRefs(mCachedTempFile));
// Write the data to disk.
@ -1537,14 +1543,12 @@ HRESULT nsDataObj::DropImage(FORMATETC& aFE, STGMEDIUM& aSTG)
outStream->Close();
GlobalUnlock(bits);
if (NS_FAILED(rv)) {
GlobalFree(bits);
if (NS_FAILED(rv))
return E_FAIL;
}
GlobalFree(bits);
// Pass the file name back to the drop target so that it can access the file.
nsAutoString path;
rv = mCachedTempFile->GetPath(path);
@ -2073,3 +2077,13 @@ HRESULT nsDataObj::GetFileContents_IStream(FORMATETC& aFE, STGMEDIUM& aSTG)
return S_OK;
}
void nsDataObj::RemoveTempFile(nsITimer* aTimer, void* aClosure)
{
nsDataObj *timedDataObj = static_cast<nsDataObj *>(aClosure);
if (timedDataObj->mCachedTempFile) {
timedDataObj->mCachedTempFile->Remove(PR_FALSE);
timedDataObj->mCachedTempFile = NULL;
}
timedDataObj->Release();
}

Просмотреть файл

@ -52,6 +52,8 @@
#include "nsIInputStream.h"
#include "nsIChannel.h"
#include "nsTPtrArray.h"
#include "nsCOMArray.h"
#include "nsITimer.h"
// XXX for older version of PSDK where IAsyncOperation and related stuff is not available
// but thisdefine should be removed when parocles config is updated
@ -333,6 +335,8 @@ class nsDataObj : public IDataObject,
BOOL fCopyIn);
IUnknown* GetCanonicalIUnknown(IUnknown *punk);
HGLOBAL GlobalClone(HGLOBAL hglobIn);
static void RemoveTempFile(nsITimer* aTimer, void* aClosure);
nsCOMPtr<nsITimer> mTimer;
};

Просмотреть файл

@ -365,30 +365,6 @@ nsDragService::StartInvokingDragSession(IDataObject * aDataObj,
SetDragEndPoint(nsIntPoint(cpos.x, cpos.y));
EndDragSession(PR_TRUE);
// For some drag/drop interactions, IDataObject::SetData doesn't get
// called with a CFSTR_PERFORMEDDROPEFFECT format and the
// intermediate file (if it was created) isn't deleted. See
// http://bugzilla.mozilla.org/show_bug.cgi?id=203847#c4 for a
// detailed description of the different cases. Now that we know
// that the drag/drop operation has ended, call SetData() so that
// the intermediate file is deleted.
static CLIPFORMAT PerformedDropEffect =
::RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT);
FORMATETC fmte =
{
(CLIPFORMAT)PerformedDropEffect,
NULL,
DVASPECT_CONTENT,
-1,
TYMED_NULL
};
STGMEDIUM medium;
medium.tymed = TYMED_NULL;
medium.pUnkForRelease = NULL;
aDataObj->SetData(&fmte, &medium, FALSE);
mDoingDrag = PR_FALSE;
return DRAGDROP_S_DROP == res ? NS_OK : NS_ERROR_FAILURE;