diff --git a/content/events/src/nsDOMDataTransfer.cpp b/content/events/src/nsDOMDataTransfer.cpp index 36d9473d781..73f6ad0f4bc 100644 --- a/content/events/src/nsDOMDataTransfer.cpp +++ b/content/events/src/nsDOMDataTransfer.cpp @@ -74,6 +74,7 @@ nsDOMDataTransfer::nsDOMDataTransfer() mEffectAllowed(nsIDragService::DRAGDROP_ACTION_UNINITIALIZED), mReadOnly(PR_FALSE), mIsExternal(PR_FALSE), + mUserCancelled(PR_FALSE), mDragImageX(0), mDragImageY(0) { @@ -84,6 +85,7 @@ nsDOMDataTransfer::nsDOMDataTransfer(PRUint32 aEventType, PRUint32 aAction) mDropEffect(nsIDragService::DRAGDROP_ACTION_NONE), mReadOnly(PR_TRUE), mIsExternal(PR_TRUE), + mUserCancelled(PR_FALSE), mDragImageX(0), mDragImageY(0) { @@ -98,6 +100,7 @@ nsDOMDataTransfer::nsDOMDataTransfer(PRUint32 aEventType, PRUint32 aAction) nsDOMDataTransfer::nsDOMDataTransfer(PRUint32 aEventType, const PRUint32 aEffectAllowed, PRBool aIsExternal, + PRBool aUserCancelled, nsTArray >& aItems, nsIDOMElement* aDragImage, PRUint32 aDragImageX, @@ -107,6 +110,7 @@ nsDOMDataTransfer::nsDOMDataTransfer(PRUint32 aEventType, mEffectAllowed(aEffectAllowed), mReadOnly(PR_TRUE), mIsExternal(aIsExternal), + mUserCancelled(aUserCancelled), mItems(aItems), mDragImage(aDragImage), mDragImageX(aDragImageX), @@ -207,6 +211,13 @@ nsDOMDataTransfer::SetEffectAllowedInt(PRUint32 aEffectAllowed) return NS_OK; } +NS_IMETHODIMP +nsDOMDataTransfer::GetMozUserCancelled(PRBool* aUserCancelled) +{ + *aUserCancelled = mUserCancelled; + return NS_OK; +} + NS_IMETHODIMP nsDOMDataTransfer::GetTypes(nsIDOMDOMStringList** aTypes) { @@ -453,11 +464,11 @@ nsDOMDataTransfer::AddElement(nsIDOMElement* aElement) } nsresult -nsDOMDataTransfer::Clone(PRUint32 aEventType, +nsDOMDataTransfer::Clone(PRUint32 aEventType, PRBool aUserCancelled, nsIDOMDataTransfer** aNewDataTransfer) { nsDOMDataTransfer* newDataTransfer = - new nsDOMDataTransfer(aEventType, mEffectAllowed, mIsExternal, + new nsDOMDataTransfer(aEventType, mEffectAllowed, mIsExternal, aUserCancelled, mItems, mDragImage, mDragImageX, mDragImageY); NS_ENSURE_TRUE(newDataTransfer, NS_ERROR_OUT_OF_MEMORY); diff --git a/content/events/src/nsDOMDataTransfer.h b/content/events/src/nsDOMDataTransfer.h index d09159f6684..669c264284d 100644 --- a/content/events/src/nsDOMDataTransfer.h +++ b/content/events/src/nsDOMDataTransfer.h @@ -94,6 +94,7 @@ protected: nsDOMDataTransfer(PRUint32 aEventType, const PRUint32 aEffectAllowed, PRBool aIsExternal, + PRBool aUserCancelled, nsTArray >& aItems, nsIDOMElement* aDragImage, PRUint32 aDragImageX, @@ -174,6 +175,9 @@ protected: // another application. PRPackedBool mIsExternal; + // true if the user cancelled the drag. Used only for the dragend event. + PRPackedBool mUserCancelled; + // array of items, each containing an array of format->data pairs nsTArray > mItems; diff --git a/content/events/src/nsDOMDragEvent.cpp b/content/events/src/nsDOMDragEvent.cpp index 292763eb87a..e159b913c3a 100644 --- a/content/events/src/nsDOMDragEvent.cpp +++ b/content/events/src/nsDOMDragEvent.cpp @@ -173,7 +173,7 @@ nsDOMDragEvent::GetDataTransfer(nsIDOMDataTransfer** aDataTransfer) nsCOMPtr initialDataTransferNS = do_QueryInterface(initialDataTransfer); NS_ENSURE_TRUE(initialDataTransferNS, NS_ERROR_FAILURE); - initialDataTransferNS->Clone(mEvent->message, + initialDataTransferNS->Clone(mEvent->message, dragEvent->userCancelled, getter_AddRefs(dragEvent->dataTransfer)); NS_ENSURE_TRUE(dragEvent->dataTransfer, NS_ERROR_OUT_OF_MEMORY); diff --git a/content/events/test/test_dragstart.html b/content/events/test/test_dragstart.html index 78ebdd8bf57..e6b5fb30197 100644 --- a/content/events/test/test_dragstart.html +++ b/content/events/test/test_dragstart.html @@ -155,6 +155,8 @@ function test_DataTransfer(dt) expectError(function() dt.mozSetDataAt("text/plain", "Some Text", 1), "NS_ERROR_DOM_INDEX_SIZE_ERR", "setDataAt index too high"); + is(dt.mozUserCancelled, false, "userCancelled"); + // because an exception occured, the data should not have been added is(dt.mozItemCount, 0, "empty setDataAt index too high itemCount"); dt.getData("text/plain", "", "empty setDataAt index too high getData"); diff --git a/dom/public/idl/events/nsIDOMDataTransfer.idl b/dom/public/idl/events/nsIDOMDataTransfer.idl index c516f28e6a3..5505a7e9729 100644 --- a/dom/public/idl/events/nsIDOMDataTransfer.idl +++ b/dom/public/idl/events/nsIDOMDataTransfer.idl @@ -154,7 +154,7 @@ interface nsIDOMDataTransfer : nsISupports void addElement(in nsIDOMElement element); }; -[scriptable, uuid(A884E56C-1678-4978-AD20-142EE94108F5)] +[scriptable, uuid(53C854FC-33F9-4647-B045-46D7AB06A6F1)] interface nsIDOMNSDataTransfer : nsISupports { /* @@ -169,9 +169,11 @@ interface nsIDOMNSDataTransfer : nsISupports [noscript] attribute unsigned long effectAllowedInt; /** - * Creates a copy of the data transfer object + * Creates a copy of the data transfer object, for the given event type and + * user cancelled flag. */ - [noscript] nsIDOMDataTransfer clone(in PRUint32 aEventType); + [noscript] nsIDOMDataTransfer clone(in PRUint32 aEventType, + in PRBool aUserCancelled); /** * The number of items being dragged. @@ -234,4 +236,11 @@ interface nsIDOMNSDataTransfer : nsISupports * @throws NS_ERROR_DOM_INDEX_SIZE_ERR if index is greater or equal than itemCount */ nsIVariant mozGetDataAt(in DOMString format, in unsigned long index); + + /** + * Will be true if the user cancelled the drag (typically by pressing Escape). + * This will be false otherwise, including if a drag failed for any other reason. + * This property is only relevant for the dragend event. + */ + readonly attribute boolean mozUserCancelled; }; diff --git a/widget/public/nsGUIEvent.h b/widget/public/nsGUIEvent.h index 094ac2ca5cc..629c84f13ed 100644 --- a/widget/public/nsGUIEvent.h +++ b/widget/public/nsGUIEvent.h @@ -775,7 +775,8 @@ class nsDragEvent : public nsMouseEvent { public: nsDragEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w) - : nsMouseEvent(isTrusted, msg, w, NS_DRAG_EVENT, eReal) + : nsMouseEvent(isTrusted, msg, w, NS_DRAG_EVENT, eReal), + userCancelled(PR_FALSE) { if (msg == NS_DRAGDROP_EXIT_SYNTH || msg == NS_DRAGDROP_LEAVE_SYNTH || @@ -785,6 +786,7 @@ public: } nsCOMPtr dataTransfer; + PRPackedBool userCancelled; }; /** diff --git a/widget/src/cocoa/nsChildView.mm b/widget/src/cocoa/nsChildView.mm index 58adf4ed316..c314453bba4 100644 --- a/widget/src/cocoa/nsChildView.mm +++ b/widget/src/cocoa/nsChildView.mm @@ -146,6 +146,7 @@ nsIWidget * gRollupWidget = nsnull; PRUint32 gLastModifierState = 0; +PRBool gUserCancelledDrag = PR_FALSE; @interface ChildView(Private) @@ -6361,6 +6362,10 @@ static BOOL keyUpAlreadySentKeyDown = NO; gDraggedTransferables = nsnull; + NSEvent *currentEvent = [NSApp currentEvent]; + gUserCancelledDrag = ([currentEvent type] == NSKeyDown && + [currentEvent keyCode] == kEscapeKeyCode); + if (!mDragService) { CallGetService(kDragServiceContractID, &mDragService); NS_ASSERTION(mDragService, "Couldn't get a drag service - big problem!"); diff --git a/widget/src/cocoa/nsDragService.mm b/widget/src/cocoa/nsDragService.mm index 78af7778d1b..ab30466470c 100644 --- a/widget/src/cocoa/nsDragService.mm +++ b/widget/src/cocoa/nsDragService.mm @@ -78,6 +78,7 @@ extern PRLogModuleInfo* sCocoaLog; extern NSPasteboard* globalDragPboard; extern NSView* gLastDragView; extern NSEvent* gLastDragEvent; +extern PRBool gUserCancelledDrag; // This global makes the transferable array available to Cocoa's promised // file destination callback. @@ -308,6 +309,7 @@ nsDragService::InvokeDragSession(nsIDOMNode* aDOMNode, nsISupportsArray* aTransf mNativeDragView = [gLastDragView retain]; mNativeDragEvent = [gLastDragEvent retain]; + gUserCancelledDrag = PR_FALSE; [mNativeDragView dragImage:image at:localPoint offset:NSMakeSize(0,0) @@ -315,6 +317,7 @@ nsDragService::InvokeDragSession(nsIDOMNode* aDOMNode, nsISupportsArray* aTransf pasteboard:[NSPasteboard pasteboardWithName:NSDragPboard] source:mNativeDragView slideBack:YES]; + gUserCancelledDrag = PR_FALSE; if (mDoingDrag) nsBaseDragService::EndDragSession(PR_FALSE); @@ -587,6 +590,8 @@ nsDragService::EndDragSession(PRBool aDoneDrag) mNativeDragEvent = nil; } + mUserCancelled = gUserCancelledDrag; + nsresult rv = nsBaseDragService::EndDragSession(aDoneDrag); mDataItems = nsnull; return rv; diff --git a/widget/src/windows/nsDragService.cpp b/widget/src/windows/nsDragService.cpp index fd4cd1b1f0c..18de557e1b5 100644 --- a/widget/src/windows/nsDragService.cpp +++ b/widget/src/windows/nsDragService.cpp @@ -270,11 +270,12 @@ nsDragService::StartInvokingDragSession(IDataObject * aDataObj, { // To do the drag we need to create an object that // implements the IDataObject interface (for OLE) - NS_IF_RELEASE(mNativeDragSrc); - mNativeDragSrc = (IDropSource *)new nsNativeDragSource(); - if (!mNativeDragSrc) + nsNativeDragSource* nativeDragSource = new nsNativeDragSource(); + if (!nativeDragSource) return NS_ERROR_OUT_OF_MEMORY; + NS_IF_RELEASE(mNativeDragSrc); + mNativeDragSrc = (IDropSource *)nativeDragSource; mNativeDragSrc->AddRef(); // Now figure out what the native drag effect should be @@ -351,7 +352,9 @@ nsDragService::StartInvokingDragSession(IDataObject * aDataObj, dataTransfer->SetDropEffectInt(DRAGDROP_ACTION_NONE); } } - + + mUserCancelled = nativeDragSource->UserCancelled(); + // We're done dragging EndDragSession(PR_TRUE); diff --git a/widget/src/windows/nsNativeDragSource.cpp b/widget/src/windows/nsNativeDragSource.cpp index 82a2810c395..46fcfb2caf3 100644 --- a/widget/src/windows/nsNativeDragSource.cpp +++ b/widget/src/windows/nsNativeDragSource.cpp @@ -44,7 +44,7 @@ * class nsNativeDragSource */ nsNativeDragSource::nsNativeDragSource() - : m_cRef(0) + : m_cRef(0), mUserCancelled(PR_FALSE) { } @@ -99,6 +99,7 @@ nsNativeDragSource::QueryContinueDrag(BOOL fEsc, DWORD grfKeyState) #ifdef DEBUG //printf("fEsc\n"); #endif + mUserCancelled = PR_TRUE; return ResultFromScode(DRAGDROP_S_CANCEL); } diff --git a/widget/src/windows/nsNativeDragSource.h b/widget/src/windows/nsNativeDragSource.h index 53606b22e5e..e194eb324e6 100644 --- a/widget/src/windows/nsNativeDragSource.h +++ b/widget/src/windows/nsNativeDragSource.h @@ -37,6 +37,7 @@ #ifndef _nsNativeDragSource_h_ #define _nsNativeDragSource_h_ +#include "nscore.h" #include #include @@ -74,11 +75,13 @@ public: // to execute the drop, otherwise NOERROR. STDMETHODIMP QueryContinueDrag(BOOL fESC, DWORD grfKeyState); + PRPackedBool UserCancelled() { return mUserCancelled; } + protected: ULONG m_cRef; // reference count - //nsIDragSource * mDragSource; // adapter - //CfDragDrop * mDragSource; // adapter + // true if the user cancelled the drag by pressing escape + PRPackedBool mUserCancelled; }; #endif // _nsNativeDragSource_h_ diff --git a/widget/src/xpwidgets/nsBaseDragService.cpp b/widget/src/xpwidgets/nsBaseDragService.cpp index 3f6d6b362fe..2bc38506654 100644 --- a/widget/src/xpwidgets/nsBaseDragService.cpp +++ b/widget/src/xpwidgets/nsBaseDragService.cpp @@ -78,7 +78,7 @@ #define DRAGIMAGES_PREF "nglayout.enable_drag_images" nsBaseDragService::nsBaseDragService() - : mCanDrop(PR_FALSE), mDoingDrag(PR_FALSE), mHasImage(PR_FALSE), + : mCanDrop(PR_FALSE), mDoingDrag(PR_FALSE), mHasImage(PR_FALSE), mUserCancelled(PR_FALSE), mDragAction(DRAGDROP_ACTION_NONE), mTargetSize(0,0), mImageX(0), mImageY(0), mScreenX(-1), mScreenY(-1), mSuppressLevel(0) { @@ -354,6 +354,7 @@ nsBaseDragService::EndDragSession(PRBool aDoneDrag) mSelection = nsnull; mDataTransfer = nsnull; mHasImage = PR_FALSE; + mUserCancelled = PR_FALSE; mImage = nsnull; mImageX = 0; mImageY = 0; @@ -373,6 +374,7 @@ nsBaseDragService::FireDragEventAtSource(PRUint32 aMsg) if (presShell) { nsEventStatus status = nsEventStatus_eIgnore; nsDragEvent event(PR_TRUE, aMsg, nsnull); + event.userCancelled = (aMsg == NS_DRAGDROP_END && mUserCancelled); nsCOMPtr content = do_QueryInterface(mSourceNode); return presShell->HandleDOMEventWithTarget(content, &event, &status); diff --git a/widget/src/xpwidgets/nsBaseDragService.h b/widget/src/xpwidgets/nsBaseDragService.h index f17e0655040..1d891ace303 100644 --- a/widget/src/xpwidgets/nsBaseDragService.h +++ b/widget/src/xpwidgets/nsBaseDragService.h @@ -129,6 +129,8 @@ protected: PRPackedBool mDoingDrag; // true if mImage should be used to set a drag image PRPackedBool mHasImage; + // true if the user cancelled the drag operation + PRPackedBool mUserCancelled; PRUint32 mDragAction; nsSize mTargetSize;