b=497498 use event coordinates for source drag end point instead of new cursor position r=roc
--- 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;