Bug 357601 - Drag and drop from an external program to Firefox does not use the proper drop effect. r=neil

This commit is contained in:
Brian R. Bondy 2011-09-01 09:48:48 -04:00
Родитель 6ff418e50f
Коммит b6d08cdd1e
2 изменённых файлов: 64 добавлений и 47 удалений

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

@ -61,7 +61,8 @@ static POINTL gDragLastPoint;
* class nsNativeDragTarget * class nsNativeDragTarget
*/ */
nsNativeDragTarget::nsNativeDragTarget(nsIWidget * aWnd) nsNativeDragTarget::nsNativeDragTarget(nsIWidget * aWnd)
: m_cRef(0), mEffect(DROPEFFECT_MOVE | DROPEFFECT_COPY | DROPEFFECT_LINK), : m_cRef(0),
mEffectsAllowed(DROPEFFECT_MOVE | DROPEFFECT_COPY | DROPEFFECT_LINK),
mTookOwnRef(PR_FALSE), mWindow(aWnd), mDropTargetHelper(nsnull) mTookOwnRef(PR_FALSE), mWindow(aWnd), mDropTargetHelper(nsnull)
{ {
mHWnd = (HWND)mWindow->GetNativeData(NS_NATIVE_WINDOW); mHWnd = (HWND)mWindow->GetNativeData(NS_NATIVE_WINDOW);
@ -126,36 +127,36 @@ void
nsNativeDragTarget::GetGeckoDragAction(DWORD grfKeyState, LPDWORD pdwEffect, nsNativeDragTarget::GetGeckoDragAction(DWORD grfKeyState, LPDWORD pdwEffect,
PRUint32 * aGeckoAction) PRUint32 * aGeckoAction)
{ {
// Default is move if we can, in fact drop here, // Only a single effect should be specified outgoing for the parameter pdwEffect.
// and if the drop source supports a move operation. // When Shift and Control are pressed, we should specify a LINK effect.
// If move is not preferred (mMovePreferred is false) if (!mMovePreferred && (grfKeyState & MK_CONTROL) &&
// move only when the shift key is down. (grfKeyState & MK_SHIFT) && (mEffectsAllowed & DROPEFFECT_LINK)) {
if ((mEffect & DROPEFFECT_MOVE) && *pdwEffect = DROPEFFECT_LINK;
(mMovePreferred || (grfKeyState & MK_SHIFT))) {
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_MOVE;
*pdwEffect = DROPEFFECT_MOVE;
}
else if (!(mEffect & DROPEFFECT_MOVE) &&
!(mEffect & DROPEFFECT_COPY) &&
(mEffect & DROPEFFECT_LINK)) {
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_LINK; *aGeckoAction = nsIDragService::DRAGDROP_ACTION_LINK;
*pdwEffect = DROPEFFECT_LINK;
} }
else { // When Shift is pressed we should specify a MOVE effect.
else if ((mEffectsAllowed & DROPEFFECT_MOVE) &&
(mMovePreferred || (grfKeyState & MK_SHIFT))) {
*pdwEffect = DROPEFFECT_MOVE;
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_MOVE;
}
// When Control is pressed we should specify a COPY effect.
else if ((mEffectsAllowed & DROPEFFECT_COPY) && (grfKeyState & MK_CONTROL)) {
*pdwEffect = DROPEFFECT_COPY;
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_COPY; *aGeckoAction = nsIDragService::DRAGDROP_ACTION_COPY;
*pdwEffect = DROPEFFECT_COPY;
} }
// Otherwise we should specify the first available effect from MOVE, COPY, or LINK.
// Given the key modifiers figure out what state we are in for both else if (mEffectsAllowed & DROPEFFECT_MOVE) {
// the native system and Gecko *pdwEffect = DROPEFFECT_MOVE;
if (grfKeyState & MK_CONTROL) { *aGeckoAction = nsIDragService::DRAGDROP_ACTION_MOVE;
if ((mEffect & DROPEFFECT_LINK) && (grfKeyState & MK_SHIFT)) { }
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_LINK; else if (mEffectsAllowed & DROPEFFECT_COPY) {
*pdwEffect = DROPEFFECT_LINK; *pdwEffect = DROPEFFECT_COPY;
} else { *aGeckoAction = nsIDragService::DRAGDROP_ACTION_COPY;
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_COPY; }
*pdwEffect = DROPEFFECT_COPY; else if (mEffectsAllowed & DROPEFFECT_LINK) {
} *pdwEffect = DROPEFFECT_LINK;
*aGeckoAction = nsIDragService::DRAGDROP_ACTION_LINK;
} }
} }
@ -219,13 +220,15 @@ nsNativeDragTarget::ProcessDrag(PRUint32 aEventType,
// Dispatch the event into Gecko // Dispatch the event into Gecko
DispatchDragDropEvent(aEventType, ptl); DispatchDragDropEvent(aEventType, ptl);
// Now get the cached Drag effect from the drag service if (aEventType != NS_DRAGDROP_DROP) {
// the data memeber should have been set by who ever handled the // Get the cached drag effect from the drag service, the data member should
// nsGUIEvent or nsIDOMEvent // have been set by whoever handled the nsGUIEvent or nsIDOMEvent on drags.
PRBool canDrop; PRBool canDrop;
currSession->GetCanDrop(&canDrop); currSession->GetCanDrop(&canDrop);
if (!canDrop) if (!canDrop) {
*pdwEffect = DROPEFFECT_NONE; *pdwEffect = DROPEFFECT_NONE;
}
}
// Clear the cached value // Clear the cached value
currSession->SetCanDrop(PR_FALSE); currSession->SetCanDrop(PR_FALSE);
@ -242,6 +245,9 @@ nsNativeDragTarget::DragEnter(LPDATAOBJECT pIDataSource,
return E_FAIL; return E_FAIL;
} }
mEffectsAllowed = *pdwEffect;
AddLinkSupportIfCanBeGenerated(pIDataSource);
// Drag and drop image helper // Drag and drop image helper
if (mDropTargetHelper) { if (mDropTargetHelper) {
POINT pt = { ptl.x, ptl.y }; POINT pt = { ptl.x, ptl.y };
@ -257,15 +263,6 @@ nsNativeDragTarget::DragEnter(LPDATAOBJECT pIDataSource,
// outside app). // outside app).
mDragService->StartDragSession(); mDragService->StartDragSession();
mEffect = *pdwEffect;
// If we don't have a link effect, but we can generate one, fix the
// drop effect to include it
if (!(mEffect & DROPEFFECT_LINK) && pIDataSource) {
if (S_OK == ::OleQueryLinkFromData(pIDataSource)) {
mEffect |= DROPEFFECT_LINK;
}
}
void* tempOutData = nsnull; void* tempOutData = nsnull;
PRUint32 tempDataLen = 0; PRUint32 tempDataLen = 0;
nsresult loadResult = nsClipboard::GetNativeDataOffClipboard( nsresult loadResult = nsClipboard::GetNativeDataOffClipboard(
@ -276,9 +273,9 @@ nsNativeDragTarget::DragEnter(LPDATAOBJECT pIDataSource,
// Mask effect coming from function call with effect preferred by the source. // Mask effect coming from function call with effect preferred by the source.
mMovePreferred = (preferredEffect & DROPEFFECT_MOVE) != 0; mMovePreferred = (preferredEffect & DROPEFFECT_MOVE) != 0;
} else {
mMovePreferred = PR_FALSE;
} }
else
mMovePreferred = (mEffect & DROPEFFECT_MOVE) != 0;
// Set the native data object into drag service // Set the native data object into drag service
// //
@ -295,6 +292,18 @@ nsNativeDragTarget::DragEnter(LPDATAOBJECT pIDataSource,
return S_OK; return S_OK;
} }
void
nsNativeDragTarget::AddLinkSupportIfCanBeGenerated(LPDATAOBJECT aIDataSource)
{
// If we don't have a link effect, but we can generate one, fix the
// drop effect to include it.
if (!(mEffectsAllowed & DROPEFFECT_LINK) && aIDataSource) {
if (S_OK == ::OleQueryLinkFromData(aIDataSource)) {
mEffectsAllowed |= DROPEFFECT_LINK;
}
}
}
STDMETHODIMP STDMETHODIMP
nsNativeDragTarget::DragOver(DWORD grfKeyState, nsNativeDragTarget::DragOver(DWORD grfKeyState,
POINTL ptl, POINTL ptl,
@ -304,6 +313,10 @@ nsNativeDragTarget::DragOver(DWORD grfKeyState,
return E_FAIL; return E_FAIL;
} }
// If a LINK effect could be generated previously from a DragEnter(),
// then we should include it as an allowed effect.
mEffectsAllowed = (*pdwEffect) | (mEffectsAllowed & DROPEFFECT_LINK);
nsCOMPtr<nsIDragSession> currentDragSession; nsCOMPtr<nsIDragSession> currentDragSession;
mDragService->GetCurrentSession(getter_AddRefs(currentDragSession)); mDragService->GetCurrentSession(getter_AddRefs(currentDragSession));
if (!currentDragSession) { if (!currentDragSession) {
@ -395,6 +408,9 @@ nsNativeDragTarget::Drop(LPDATAOBJECT pData,
return E_FAIL; return E_FAIL;
} }
mEffectsAllowed = *pdwEffect;
AddLinkSupportIfCanBeGenerated(pData);
// Drag and drop image helper // Drag and drop image helper
if (mDropTargetHelper) { if (mDropTargetHelper) {
POINT pt = { aPT.x, aPT.y }; POINT pt = { aPT.x, aPT.y };

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

@ -107,11 +107,12 @@ protected:
void ProcessDrag(PRUint32 aEventType, DWORD grfKeyState, void ProcessDrag(PRUint32 aEventType, DWORD grfKeyState,
POINTL pt, DWORD* pdwEffect); POINTL pt, DWORD* pdwEffect);
void DispatchDragDropEvent(PRUint32 aType, POINTL pt); void DispatchDragDropEvent(PRUint32 aType, POINTL pt);
void AddLinkSupportIfCanBeGenerated(LPDATAOBJECT aIDataSource);
// Native Stuff // Native Stuff
ULONG m_cRef; // reference count ULONG m_cRef; // reference count
HWND mHWnd; HWND mHWnd;
DWORD mEffect; DWORD mEffectsAllowed;
PRBool mMovePreferred; PRBool mMovePreferred;
PRBool mTookOwnRef; PRBool mTookOwnRef;