Bug 1329997: Ensure that we don't initiate drag sessions if the system has already sent a mouseUp event. This prevents getting stuck in drag sessions. r=mstange
authorStephen A Pohl <spohl.mozilla.bugs@gmail.com>
Wed, 15 Feb 2017 18:46:02 -0500
changeset 343225 f5d3690285980b574bd87d2b1bfbd81de5964a57
parent 343224 492fa407d12ca8ef6adf35051cee7356d75ac2c1
child 343226 0b83dd97c786bfc2641d1733e278faa35475d09c
push id31372
push usercbook@mozilla.com
push dateThu, 16 Feb 2017 12:16:10 +0000
treeherdermozilla-central@2737f66ad6ac [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1329997
milestone54.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 1329997: Ensure that we don't initiate drag sessions if the system has already sent a mouseUp event. This prevents getting stuck in drag sessions. r=mstange
widget/cocoa/nsDragService.mm
--- a/widget/cocoa/nsDragService.mm
+++ b/widget/cocoa/nsDragService.mm
@@ -272,34 +272,39 @@ nsDragService::GetFilePath(NSPasteboardI
     }
   }
 
   return nil;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
 }
 
-// We can only invoke NSView's 'dragImage:at:offset:event:pasteboard:source:slideBack:' from
-// within NSView's 'mouseDown:' or 'mouseDragged:'. Luckily 'mouseDragged' is always on the
-// stack when InvokeDragSession gets called.
 nsresult
 nsDragService::InvokeDragSessionImpl(nsIArray* aTransferableArray,
                                      nsIScriptableRegion* aDragRgn,
                                      uint32_t aActionType)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
 
+  if (!gLastDragView) {
+    // gLastDragView is only set during -[ChildView mouseDragged:].
+    // InvokeDragSessionImpl is only called while Gecko processes a mouse move
+    // event. So if we get here with gLastDragView being null, that means that
+    // the mouse button has already been released, and mouseMoved is on the
+    // stack instead of mouseDragged. In that case we need to abort the drag
+    // because the OS won't know where to drop whatever's being dragged, and we
+    // might end up with a stuck drag & drop session.
+    return NS_ERROR_FAILURE;
+  }
+
   mDataItems = aTransferableArray;
 
   // Save the transferables away in case a promised file callback is invoked.
   gDraggedTransferables = aTransferableArray;
 
-  nsBaseDragService::StartDragSession();
-  nsBaseDragService::OpenDragPopup();
-
   // We need to retain the view and the event during the drag in case either
   // gets destroyed.
   mNativeDragView = [gLastDragView retain];
   mNativeDragEvent = [gLastDragMouseDownEvent retain];
 
   gUserCancelledDrag = false;
 
   NSPasteboardItem* pbItem = [NSPasteboardItem new];
@@ -340,16 +345,19 @@ nsDragService::InvokeDragSessionImpl(nsI
   localDragRect.origin.x = draggingPoint.x;
   localDragRect.origin.y = draggingPoint.y - localDragRect.size.height;
 
   NSDraggingItem* dragItem =
     [[NSDraggingItem alloc] initWithPasteboardWriter:pbItem];
   [pbItem release];
   [dragItem setDraggingFrame:localDragRect contents:image];
 
+  nsBaseDragService::StartDragSession();
+  nsBaseDragService::OpenDragPopup();
+
   NSDraggingSession* draggingSession =
     [mNativeDragView beginDraggingSessionWithItems:
         [NSArray arrayWithObject:[dragItem autorelease]]
                                              event:mNativeDragEvent
                                             source:mNativeDragView];
   draggingSession.animatesToStartingPositionsOnCancelOrFail = YES;
 
   return NS_OK;