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 91816 8bea9978c445a4a6dac7f2d05796e113746ce863
parent 91815 fadcc45f8fe80aa5a52c96cf1422efc31981faab
child 91817 93a7a0655014286756c8691e6a3cbe4882b33534
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersroc
bugs497498
milestone14.0a1
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;