b=497498 use event coordinates for source drag end point instead of new cursor position r=roc
authorKarl Tomlinson <karlt+@karlt.net>
Tue, 17 Apr 2012 13:00:25 +1200
changeset 91811 8bea9978c445a4a6dac7f2d05796e113746ce863
parent 91810 fadcc45f8fe80aa5a52c96cf1422efc31981faab
child 91812 93a7a0655014286756c8691e6a3cbe4882b33534
push id8402
push userktomlinson@mozilla.com
push dateTue, 17 Apr 2012 05:01:09 +0000
treeherdermozilla-inbound@96e8cc4b2b20 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs497498
milestone14.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
b=497498 use event coordinates for source drag end point instead of new cursor position r=roc
widget/gtk2/nsDragService.cpp
--- a/widget/gtk2/nsDragService.cpp
+++ b/widget/gtk2/nsDragService.cpp
@@ -263,18 +263,30 @@ DispatchMotionEventCopy(gpointer aData)
 static void
 OnSourceGrabEventAfter(GtkWidget *widget, GdkEvent *event, gpointer user_data)
 {
     if (event->type != GDK_MOTION_NOTIFY)
         return;
 
     if (sMotionEventTimerID) {
         g_source_remove(sMotionEventTimerID);
+        sMotionEventTimerID = 0;
     }
 
+    // If there is no longer a grab on the widget, then the drag motion is
+    // over (though the data may not be fetched yet).
+    if (gtk_grab_get_current() != widget)
+        return;
+
+    // Update the cursor position.  The last of these recorded gets used for
+    // the NS_DRAGDROP_END event.
+    nsDragService *dragService = static_cast<nsDragService*>(user_data);
+    dragService->
+        SetDragEndPoint(nsIntPoint(event->motion.x_root, event->motion.y_root));
+
     MotionEventData *data = new MotionEventData(widget, event);
 
     // G_PRIORITY_DEFAULT_IDLE is lower priority than GDK's redraw idle source
     // and lower than GTK's idle source that sends drag position messages after
     // motion-notify signals.
     //
     // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#drag-and-drop-processing-model
     // recommends an interval of 350ms +/- 200ms.
@@ -347,18 +359,20 @@ nsDragService::InvokeDragSession(nsIDOMN
 
         // GTK uses another hidden window for receiving mouse events.
         mGrabWidget = gtk_grab_get_current();
         if (mGrabWidget) {
             g_object_ref(mGrabWidget);
             // Only motion events are required but connect to
             // "event-after" as this is never blocked by other handlers.
             g_signal_connect(mGrabWidget, "event-after",
-                             G_CALLBACK(OnSourceGrabEventAfter), NULL);
+                             G_CALLBACK(OnSourceGrabEventAfter), this);
         }
+        // We don't have a drag end point yet.
+        mEndDragPoint = nsIntPoint(-1, -1);
     }
     else {
         rv = NS_ERROR_FAILURE;
     }
 
     gtk_target_list_unref(sourceList);
 
     return rv;
@@ -424,17 +438,17 @@ nsDragService::StartDragSession()
 NS_IMETHODIMP
 nsDragService::EndDragSession(bool aDoneDrag)
 {
     PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::EndDragSession %d",
                                    aDoneDrag));
 
     if (mGrabWidget) {
         g_signal_handlers_disconnect_by_func(mGrabWidget,
-             FuncToGpointer(OnSourceGrabEventAfter), NULL);
+             FuncToGpointer(OnSourceGrabEventAfter), this);
         g_object_unref(mGrabWidget);
         mGrabWidget = NULL;
 
         if (sMotionEventTimerID) {
             g_source_remove(sMotionEventTimerID);
             sMotionEventTimerID = 0;
         }
     }
@@ -1321,21 +1335,24 @@ nsDragService::SourceEndDragSession(GdkD
                                     gint            aResult)
 {
     // this just releases the list of data items that we provide
     mSourceDataItems = nsnull;
 
     if (!mDoingDrag)
         return; // EndDragSession() was already called on drop or drag-failed
 
-    gint x, y;
-    GdkDisplay* display = gdk_display_get_default();
-    if (display) {
-      gdk_display_get_pointer(display, NULL, &x, &y, NULL);
-      SetDragEndPoint(nsIntPoint(x, y));
+    if (mEndDragPoint.x < 0) {
+        // We don't have a drag end point, so guess
+        gint x, y;
+        GdkDisplay* display = gdk_display_get_default();
+        if (display) {
+            gdk_display_get_pointer(display, NULL, &x, &y, NULL);
+            SetDragEndPoint(nsIntPoint(x, y));
+        }
     }
 
     // Either the drag was aborted or the drop occurred outside the app.
     // The dropEffect of mDataTransfer is not updated for motion outside the
     // app, but is needed for the dragend event, so set it now.
 
     PRUint32 dropEffect;