retain drag source view during drag in case gecko kills off the view during the drag. b=396829 r=smichaud sr=roc a=roc
authorjoshmoz@gmail.com
Sun, 23 Sep 2007 17:01:04 -0700
changeset 6245 3c9f133941238a51b3326e3141b7d9e09fa8b907
parent 6244 155cd7bdd7d9142a33937b5c88dd363c72129bd8
child 6246 d39b39e78f886be098b7a95688349bc8bca60408
push id1
push userbsmedberg@mozilla.com
push dateThu, 20 Mar 2008 16:49:24 +0000
treeherdermozilla-central@61007906a1f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmichaud, roc, roc
bugs396829
milestone1.9a9pre
retain drag source view during drag in case gecko kills off the view during the drag. b=396829 r=smichaud sr=roc a=roc
widget/src/cocoa/nsChildView.mm
widget/src/cocoa/nsDragService.h
widget/src/cocoa/nsDragService.mm
--- a/widget/src/cocoa/nsChildView.mm
+++ b/widget/src/cocoa/nsChildView.mm
@@ -1779,23 +1779,23 @@ nsChildView::GetDocumentAccessible(nsIAc
 
 // globalDragPboard is non-null during native drag sessions that did not originate
 // in our native NSView (it is set in |draggingEntered:|). It is unset when the
 // drag session ends for this view, either with the mouse exiting or when a drop
 // occurs in this view.
 NSPasteboard* globalDragPboard = nil;
 
 
-// globalDragView and globalDragEvent are only non-null during calls to |mouseDragged:|
+// gLastDragView and gLastDragEvent are only non-null during calls to |mouseDragged:|
 // in our native NSView. They are used to communicate information to the drag service
 // during drag invocation (starting a drag in from the view). All drag service drag
 // invocations happen only while these two global variables are non-null, while |mouseDragged:|
 // is on the stack.
-NSView* globalDragView = nil;
-NSEvent* globalDragEvent = nil;
+NSView* gLastDragView = nil;
+NSEvent* gLastDragEvent = nil;
 
 
 // initWithFrame:geckoChild:eventSink:
 - (id)initWithFrame:(NSRect)inFrame geckoChild:(nsChildView*)inChild eventSink:(nsIEventSink*)inSink
 {
   if ((self = [super initWithFrame:inFrame])) {
     mGeckoChild = inChild;
     mIsPluginView = NO;
@@ -2777,35 +2777,35 @@ static nsEventStatus SendGeckoMouseEnter
     return;
 
   // if the handscroll flag is set, steal this event
   if (mInHandScroll) {
     [self updateHandScroll:theEvent];
     return;
   }
 
-  globalDragView = self;
-  globalDragEvent = theEvent;
+  gLastDragView = self;
+  gLastDragEvent = theEvent;
 
   nsMouseEvent geckoEvent(PR_TRUE, NS_MOUSE_MOVE, nsnull, nsMouseEvent::eReal);
   [self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent];
 
   // create native EventRecord for use by plugins
   EventRecord macEvent;
   macEvent.what = nullEvent;
   macEvent.message = 0;
   macEvent.when = ::TickCount();
   ::GetGlobalMouse(&macEvent.where);
   macEvent.modifiers = btnState | GetCurrentKeyModifiers();
   geckoEvent.nativeMsg = &macEvent;
 
   mGeckoChild->DispatchMouseEvent(geckoEvent);    
 
-  globalDragView = nil;
-  globalDragEvent = nil;
+  gLastDragView = nil;
+  gLastDragEvent = nil;
   // XXX maybe call markedTextSelectionChanged:client: here?
 }
 
 
 - (void)rightMouseDown:(NSEvent *)theEvent
 {  
   // Make sure this view is not in the rollup widget. The fastest way to do this
   // is by comparing native window pointers. Also don't roll up if we just put
--- a/widget/src/cocoa/nsDragService.h
+++ b/widget/src/cocoa/nsDragService.h
@@ -63,11 +63,13 @@ public:
 
 private:
 
   NSImage* ConstructDragImage(nsIDOMNode* aDOMNode,
                               nsRect* aDragRect,
                               nsIScriptableRegion* aRegion);
 
   nsCOMPtr<nsISupportsArray> mDataItems; // only valid for a drag started within gecko
+  NSView* mNativeDragView;
+  NSEvent* mNativeDragEvent;
 };
 
 #endif // nsDragService_h_
--- a/widget/src/cocoa/nsDragService.mm
+++ b/widget/src/cocoa/nsDragService.mm
@@ -70,27 +70,29 @@
 #endif
 #include "prlog.h"
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* sCocoaLog;
 #endif
 
 extern NSPasteboard* globalDragPboard;
-extern NSView* globalDragView;
-extern NSEvent* globalDragEvent;
+extern NSView* gLastDragView;
+extern NSEvent* gLastDragEvent;
 
 // This global makes the transferable array available to Cocoa's promised
 // file destination callback.
 nsISupportsArray *gDraggedTransferables = nsnull;
 
 NSString* const kWildcardPboardType = @"MozillaWildcard";
 
 nsDragService::nsDragService()
 {
+  mNativeDragView = nil;
+  mNativeDragEvent = nil;
 }
 
 
 nsDragService::~nsDragService()
 {
 }
 
 static nsresult SetUpDragClipboard(nsISupportsArray* aTransferableArray)
@@ -145,17 +147,17 @@ static nsresult SetUpDragClipboard(nsISu
 }
 
 
 NSImage*
 nsDragService::ConstructDragImage(nsIDOMNode* aDOMNode,
                                   nsRect* aDragRect,
                                   nsIScriptableRegion* aRegion)
 {
-  NSPoint screenPoint = [[globalDragView window] convertBaseToScreen:[globalDragEvent locationInWindow]];
+  NSPoint screenPoint = [[gLastDragView window] convertBaseToScreen:[gLastDragEvent locationInWindow]];
   // Y coordinates are bottom to top, so reverse this
   if ([[NSScreen screens] count] > 0)
     screenPoint.y = NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]) - screenPoint.y;
 
   nsRefPtr<gfxASurface> surface;
   nsresult rv = DrawDrag(aDOMNode, aRegion,
                          NSToIntRound(screenPoint.x), NSToIntRound(screenPoint.y),
                          aDragRect, getter_AddRefs(surface));
@@ -264,31 +266,35 @@ nsDragService::InvokeDragSession(nsIDOMN
 
   NSPoint point;
   point.x = dragRect.x;
   if ([[NSScreen screens] count] > 0)
     point.y = NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]) - dragRect.YMost();
   else
     point.y = dragRect.y;
 
-  point = [[globalDragView window] convertScreenToBase: point];
-  NSPoint localPoint = [globalDragView convertPoint:point fromView:nil];
+  point = [[gLastDragView window] convertScreenToBase: point];
+  NSPoint localPoint = [gLastDragView convertPoint:point fromView:nil];
  
   // Save the transferables away in case a promised file callback is invoked.
   gDraggedTransferables = aTransferableArray;
 
   nsBaseDragService::StartDragSession();
 
-  [globalDragView dragImage:image
-                         at:localPoint
-                     offset:NSMakeSize(0,0)
-                      event:globalDragEvent
-                 pasteboard:[NSPasteboard pasteboardWithName:NSDragPboard]
-                     source:globalDragView
-                  slideBack:YES];
+  // We need to retain the view and the event during the drag in case either gets destroyed.
+  mNativeDragView = [gLastDragView retain];
+  mNativeDragEvent = [gLastDragEvent retain];
+
+  [mNativeDragView dragImage:image
+                          at:localPoint
+                      offset:NSMakeSize(0,0)
+                       event:mNativeDragEvent
+                  pasteboard:[NSPasteboard pasteboardWithName:NSDragPboard]
+                      source:mNativeDragView
+                   slideBack:YES];
 
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsDragService::GetData(nsITransferable* aTransferable, PRUint32 aItemIndex)
 {
@@ -511,11 +517,20 @@ nsDragService::GetNumDropItems(PRUint32*
   
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsDragService::EndDragSession(PRBool aDoneDrag)
 {
+  if (mNativeDragView) {
+    [mNativeDragView release];
+    mNativeDragView = nil;
+  }
+  if (mNativeDragEvent) {
+    [mNativeDragEvent release];
+    mNativeDragEvent = nil;
+  }
+
   mDataItems = nsnull;
   return nsBaseDragService::EndDragSession(aDoneDrag);
 }