Bug 673080 - Dropping a link on Firefox from an external program has no effect. r=neil
authorBrian R. Bondy <netzen@gmail.com>
Thu, 01 Sep 2011 09:48:48 -0400
changeset 77689 89c47cdfad0a20e111ccea68d1c492df4d2fc410
parent 77688 56bb9cbd6c26defa6a9f55dec9bd8509d9f0fdfd
child 77690 2c6b5f33faa63f98dc8a88b4a0ab0ce271315ed2
push id78
push userclegnitto@mozilla.com
push dateFri, 16 Dec 2011 17:32:24 +0000
treeherdermozilla-release@79d24e644fdd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersneil
bugs673080
milestone9.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 673080 - Dropping a link on Firefox from an external program has no effect. r=neil
widget/src/windows/nsNativeDragTarget.cpp
widget/src/windows/nsNativeDragTarget.h
--- a/widget/src/windows/nsNativeDragTarget.cpp
+++ b/widget/src/windows/nsNativeDragTarget.cpp
@@ -56,18 +56,18 @@ static NS_DEFINE_IID(kIDragServiceIID, N
 
 // This is cached for Leave notification
 static POINTL gDragLastPoint;
 
 /*
  * class nsNativeDragTarget
  */
 nsNativeDragTarget::nsNativeDragTarget(nsIWidget * aWnd)
-  : m_cRef(0), mCanMove(PR_TRUE), mTookOwnRef(PR_FALSE), mWindow(aWnd),
-  mDropTargetHelper(nsnull)
+  : m_cRef(0), mEffect(DROPEFFECT_MOVE | DROPEFFECT_COPY | DROPEFFECT_LINK), 
+    mTookOwnRef(PR_FALSE), mWindow(aWnd), mDropTargetHelper(nsnull)
 {
   mHWnd = (HWND)mWindow->GetNativeData(NS_NATIVE_WINDOW);
 
   /*
    * Create/Get the DragService that we have implemented
    */
   CallGetService(kCDragServiceCID, &mDragService);
 
@@ -118,41 +118,43 @@ STDMETHODIMP_(ULONG) nsNativeDragTarget:
   if (0 != m_cRef)
     return m_cRef;
 
   delete this;
   return 0;
 }
 
 void
-nsNativeDragTarget::GetGeckoDragAction(LPDATAOBJECT pData, DWORD grfKeyState,
-                                       LPDWORD pdwEffect,
+nsNativeDragTarget::GetGeckoDragAction(DWORD grfKeyState, LPDWORD pdwEffect,
                                        PRUint32 * aGeckoAction)
-{
-  // Check if we can link from this data object as well.
-  PRBool canLink = PR_FALSE;
-  if (pData)
-    canLink = (S_OK == ::OleQueryLinkFromData(pData) ? PR_TRUE : PR_FALSE);
-
+{  
   // Default is move if we can, in fact drop here,
   // and if the drop source supports a move operation.
   // If move is not preferred (mMovePreferred is false)
   // move only when the shift key is down.
-  if (mCanMove && (mMovePreferred || (grfKeyState & MK_SHIFT))) {
+  if ((mEffect & DROPEFFECT_MOVE) && 
+      (mMovePreferred || (grfKeyState & MK_SHIFT))) {
     *aGeckoAction = nsIDragService::DRAGDROP_ACTION_MOVE;
     *pdwEffect    = DROPEFFECT_MOVE;
-  } else {
+  } 
+  else if (!(mEffect & DROPEFFECT_MOVE) && 
+           !(mEffect & DROPEFFECT_COPY) && 
+           (mEffect & DROPEFFECT_LINK)) {
+    *aGeckoAction = nsIDragService::DRAGDROP_ACTION_LINK;
+    *pdwEffect    = DROPEFFECT_LINK;
+  }
+  else {
     *aGeckoAction = nsIDragService::DRAGDROP_ACTION_COPY;
     *pdwEffect    = DROPEFFECT_COPY;
   }
 
   // Given the key modifiers figure out what state we are in for both
   // the native system and Gecko
   if (grfKeyState & MK_CONTROL) {
-    if (canLink && (grfKeyState & MK_SHIFT)) {
+    if ((mEffect & DROPEFFECT_LINK) && (grfKeyState & MK_SHIFT)) {
       *aGeckoAction = nsIDragService::DRAGDROP_ACTION_LINK;
       *pdwEffect    = DROPEFFECT_LINK;
     } else {
       *aGeckoAction = nsIDragService::DRAGDROP_ACTION_COPY;
       *pdwEffect    = DROPEFFECT_COPY;
     }
   }
 }
@@ -191,25 +193,24 @@ nsNativeDragTarget::DispatchDragDropEven
   event.isMeta    = PR_FALSE;
   event.isAlt     = IsKeyDown(NS_VK_ALT);
   event.inputSource = static_cast<nsBaseDragService*>(mDragService)->GetInputSource();
 
   mWindow->DispatchEvent(&event, status);
 }
 
 void
-nsNativeDragTarget::ProcessDrag(LPDATAOBJECT pData,
-                                PRUint32     aEventType,
+nsNativeDragTarget::ProcessDrag(PRUint32     aEventType,
                                 DWORD        grfKeyState,
                                 POINTL       ptl,
                                 DWORD*       pdwEffect)
 {
   // Before dispatching the event make sure we have the correct drop action set
   PRUint32 geckoAction;
-  GetGeckoDragAction(pData, grfKeyState, pdwEffect, &geckoAction);
+  GetGeckoDragAction(grfKeyState, pdwEffect, &geckoAction);
 
   // Set the current action into the Gecko specific type
   nsCOMPtr<nsIDragSession> currSession;
   mDragService->GetCurrentSession(getter_AddRefs(currSession));
   if (!currSession) {
     return;
   }
 
@@ -251,44 +252,50 @@ nsNativeDragTarget::DragEnter(LPDATAOBJE
   NS_ASSERTION(!mTookOwnRef, "own ref already taken!");
   this->AddRef();
   mTookOwnRef = PR_TRUE;
 
   // tell the drag service about this drag (it may have come from an
   // outside app).
   mDragService->StartDragSession();
 
-  // Remember if this operation allows a move.
-  mCanMove = (*pdwEffect) & DROPEFFECT_MOVE;
+  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;
   PRUint32 tempDataLen = 0;
   nsresult loadResult = nsClipboard::GetNativeDataOffClipboard(
       pIDataSource, 0, ::RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT), nsnull, &tempOutData, &tempDataLen);
   if (NS_SUCCEEDED(loadResult) && tempOutData) {
     NS_ASSERTION(tempDataLen == 2, "Expected word size");
     WORD preferredEffect = *((WORD*)tempOutData);
 
     // Mask effect coming from function call with effect preferred by the source.
     mMovePreferred = (preferredEffect & DROPEFFECT_MOVE) != 0;
   }
   else
-    mMovePreferred = mCanMove;
+    mMovePreferred = (mEffect & DROPEFFECT_MOVE) != 0;
 
   // Set the native data object into drag service
   //
   // This cast is ok because in the constructor we created a
   // the actual implementation we wanted, so we know this is
   // a nsDragService. It should be a private interface, though.
   nsDragService * winDragService =
     static_cast<nsDragService *>(mDragService);
   winDragService->SetIDataObject(pIDataSource);
 
   // Now process the native drag state and then dispatch the event
-  ProcessDrag(pIDataSource, NS_DRAGDROP_ENTER, grfKeyState, ptl, pdwEffect);
+  ProcessDrag(NS_DRAGDROP_ENTER, grfKeyState, ptl, pdwEffect);
 
   return S_OK;
 }
 
 STDMETHODIMP
 nsNativeDragTarget::DragOver(DWORD   grfKeyState,
                              POINTL  ptl,
                              LPDWORD pdwEffect)
@@ -309,17 +316,17 @@ nsNativeDragTarget::DragOver(DWORD   grf
   // Drag and drop image helper
   if (mDropTargetHelper) {
     POINT pt = { ptl.x, ptl.y };
     mDropTargetHelper->DragOver(&pt, *pdwEffect);
   }
 
   mDragService->FireDragEventAtSource(NS_DRAGDROP_DRAG);
   // Now process the native drag state and then dispatch the event
-  ProcessDrag(nsnull, NS_DRAGDROP_OVER, grfKeyState, ptl, pdwEffect);
+  ProcessDrag(NS_DRAGDROP_OVER, grfKeyState, ptl, pdwEffect);
 
   this->Release();
 
   return S_OK;
 }
 
 STDMETHODIMP
 nsNativeDragTarget::DragLeave()
@@ -403,17 +410,17 @@ nsNativeDragTarget::Drop(LPDATAOBJECT pD
   winDragService->SetIDataObject(pData);
 
   // NOTE: ProcessDrag spins the event loop which may destroy arbitrary objects.
   // We use strong refs to prevent it from destroying these:
   nsRefPtr<nsNativeDragTarget> kungFuDeathGrip = this;
   nsCOMPtr<nsIDragService> serv = mDragService;
 
   // Now process the native drag state and then dispatch the event
-  ProcessDrag(pData, NS_DRAGDROP_DROP, grfKeyState, aPT, pdwEffect);
+  ProcessDrag(NS_DRAGDROP_DROP, grfKeyState, aPT, pdwEffect);
 
   nsCOMPtr<nsIDragSession> currentDragSession;
   serv->GetCurrentSession(getter_AddRefs(currentDragSession));
   if (!currentDragSession) {
     return S_OK;  // DragCancel() was called.
   }
 
   // Let the win drag service know whether this session experienced 
--- a/widget/src/windows/nsNativeDragTarget.h
+++ b/widget/src/windows/nsNativeDragTarget.h
@@ -97,26 +97,26 @@ public:
                     POINTL point, DWORD* pEffect);
   /**
    * Cancel the current drag session, if any.
    */
   void DragCancel();
 
 protected:
 
-  void GetGeckoDragAction(LPDATAOBJECT pData, DWORD grfKeyState,
-                          LPDWORD pdwEffect, PRUint32 * aGeckoAction);
-  void ProcessDrag(LPDATAOBJECT pData, PRUint32 aEventType, DWORD grfKeyState,
+  void GetGeckoDragAction(DWORD grfKeyState, LPDWORD pdwEffect, 
+                          PRUint32 * aGeckoAction);
+  void ProcessDrag(PRUint32 aEventType, DWORD grfKeyState,
                    POINTL pt, DWORD* pdwEffect);
   void DispatchDragDropEvent(PRUint32 aType, POINTL pt);
 
   // Native Stuff
   ULONG            m_cRef;      // reference count
   HWND             mHWnd;
-  PRBool           mCanMove;
+  DWORD            mEffect;
   PRBool           mMovePreferred;
   PRBool           mTookOwnRef;
 
   // Gecko Stuff
   nsIWidget      * mWindow;
   nsIDragService * mDragService;
 
   // Drag target helper