Bug 539862, Call TargetSetLastContext and UpdateDragStatus before dragenter is fired so drag action and window are properly set up, fixes dragging themes into addons dialog, r=karlt
authorNeil Deakin <neil@mozilla.com>
Mon, 01 Feb 2010 10:11:09 -0500
changeset 37793 4ab5e6695dc88305a402b1d5daaac4107c7022d8
parent 37792 0538dc4319643594cd6f685d30d67f1c9bd01050
child 37794 f1cf6e5613517af27148cd4d216438c1cc8dcdb8
push id11436
push userneil@mozilla.com
push dateMon, 01 Feb 2010 15:13:06 +0000
treeherdermozilla-central@4ab5e6695dc8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskarlt
bugs539862
milestone1.9.3a1pre
Bug 539862, Call TargetSetLastContext and UpdateDragStatus before dragenter is fired so drag action and window are properly set up, fixes dragging themes into addons dialog, r=karlt
widget/src/gtk2/nsWindow.cpp
widget/src/gtk2/nsWindow.h
--- a/widget/src/gtk2/nsWindow.cpp
+++ b/widget/src/gtk2/nsWindow.cpp
@@ -3604,16 +3604,46 @@ nsWindow::ThemeChanged()
             nsRefPtr<nsWindow> kungFuDeathGrip = win;
             win->ThemeChanged();
         }
 
         children = children->next;
     }
 }
 
+void
+nsWindow::CheckNeedDragLeaveEnter(nsWindow* aInnerMostWidget,
+                                  nsIDragService* aDragService,
+                                  GdkDragContext *aDragContext,
+                                  nscoord aX, nscoord aY)
+{
+    // check to see if there was a drag motion window already in place
+    if (mLastDragMotionWindow) {
+        // same as the last window so no need for dragenter and dragleave events
+        if (mLastDragMotionWindow == aInnerMostWidget) {
+            UpdateDragStatus(aDragContext, aDragService);
+            return;
+        }
+
+        // send a dragleave event to the last window that got a motion event
+        nsRefPtr<nsWindow> kungFuDeathGrip = mLastDragMotionWindow;
+        mLastDragMotionWindow->OnDragLeave();
+    }
+
+    // Make sure that the drag service knows we're now dragging
+    aDragService->StartDragSession();
+
+    // update our drag status and send a dragenter event to the window
+    UpdateDragStatus(aDragContext, aDragService);
+    aInnerMostWidget->OnDragEnter(aX, aY);
+
+    // set the last window to the innerMostWidget
+    mLastDragMotionWindow = aInnerMostWidget;
+}
+
 gboolean
 nsWindow::OnDragMotionEvent(GtkWidget *aWidget,
                             GdkDragContext *aDragContext,
                             gint aX,
                             gint aY,
                             guint aTime,
                             gpointer aData)
 {
@@ -3652,52 +3682,37 @@ nsWindow::OnDragMotionEvent(GtkWidget *a
 
     GdkWindow *innerWindow = get_inner_gdk_window(aWidget->window, aX, aY,
                                                   &retx, &rety);
     nsRefPtr<nsWindow> innerMostWidget = get_window_for_gdk_window(innerWindow);
 
     if (!innerMostWidget)
         innerMostWidget = this;
 
-    // check to see if there was a drag motion window already in place
-    if (mLastDragMotionWindow) {
-        // if it wasn't this
-        if (mLastDragMotionWindow != innerMostWidget) {
-            // send a drag event to the last window that got a motion event
-            nsRefPtr<nsWindow> kungFuDeathGrip = mLastDragMotionWindow;
-            mLastDragMotionWindow->OnDragLeave();
-            // and enter on the new one
-            innerMostWidget->OnDragEnter(retx, rety);
-        }
-    }
-    else {
-        // if there was no other motion window, then we're starting a
-        // drag. Send an enter event to initiate the drag.
-
-        innerMostWidget->OnDragEnter(retx, rety);
-    }
-
-    // set the last window to the innerMostWidget
-    mLastDragMotionWindow = innerMostWidget;
-
     // update the drag context
     dragSessionGTK->TargetSetLastContext(aWidget, aDragContext, aTime);
 
+    // clear any drag leave timer that might be pending so that it
+    // doesn't get processed when we actually go out to get data.
+    if (mDragLeaveTimer) {
+        mDragLeaveTimer->Cancel();
+        mDragLeaveTimer = nsnull;
+    }
+
+    CheckNeedDragLeaveEnter(innerMostWidget, dragService, aDragContext, retx, rety);
+
     // notify the drag service that we are starting a drag motion.
     dragSessionGTK->TargetStartDragMotion();
 
     dragService->FireDragEventAtSource(NS_DRAGDROP_DRAG);
 
     nsDragEvent event(PR_TRUE, NS_DRAGDROP_OVER, innerMostWidget);
 
     InitDragEvent(event);
 
-    // now that we have initialized the event update our drag status
-    UpdateDragStatus(event, aDragContext, dragService);
-
     event.refPoint.x = retx;
     event.refPoint.y = rety;
     event.time = aTime;
 
     nsEventStatus status;
     innerMostWidget->DispatchEvent(&event, status);
 
     // we're done with the drag motion event.  notify the drag service.
@@ -3756,60 +3771,39 @@ nsWindow::OnDragDropEvent(GtkWidget *aWi
 
     nscoord retx = 0;
     nscoord rety = 0;
 
     GdkWindow *innerWindow = get_inner_gdk_window(aWidget->window, aX, aY,
                                                   &retx, &rety);
     nsRefPtr<nsWindow> innerMostWidget = get_window_for_gdk_window(innerWindow);
 
-    // set this now before any of the drag enter or leave events happen
-    dragSessionGTK->TargetSetLastContext(aWidget, aDragContext, aTime);
-
     if (!innerMostWidget)
         innerMostWidget = this;
 
-    // check to see if there was a drag motion window already in place
-    if (mLastDragMotionWindow) {
-        // if it wasn't this
-        if (mLastDragMotionWindow != innerMostWidget) {
-            // send a drag event to the last window that got a motion event
-            nsRefPtr<nsWindow> kungFuDeathGrip = mLastDragMotionWindow;
-            mLastDragMotionWindow->OnDragLeave();
-            // and enter on the new one
-            innerMostWidget->OnDragEnter(retx, rety);
-        }
-    }
-    else {
-        // if there was no other motion window, send an enter event to
-        // initiate the drag session.
-        innerMostWidget->OnDragEnter(retx, rety);
-    }
+    // set this now before any of the drag enter or leave events happen
+    dragSessionGTK->TargetSetLastContext(aWidget, aDragContext, aTime);
 
     // clear any drag leave timer that might be pending so that it
     // doesn't get processed when we actually go out to get data.
     if (mDragLeaveTimer) {
         mDragLeaveTimer->Cancel();
         mDragLeaveTimer = nsnull;
     }
 
-    // set the last window to this
-    mLastDragMotionWindow = innerMostWidget;
+    CheckNeedDragLeaveEnter(innerMostWidget, dragService, aDragContext, retx, rety);
 
     // What we do here is dispatch a new drag motion event to
     // re-validate the drag target and then we do the drop.  The events
     // look the same except for the type.
 
     nsDragEvent event(PR_TRUE, NS_DRAGDROP_OVER, innerMostWidget);
 
     InitDragEvent(event);
 
-    // now that we have initialized the event update our drag status
-    UpdateDragStatus(event, aDragContext, dragService);
-
     event.refPoint.x = retx;
     event.refPoint.y = rety;
     event.time = aTime;
 
     nsEventStatus status;
     innerMostWidget->DispatchEvent(&event, status);
 
     // We need to check innerMostWidget->mIsDestroyed here because the nsRefPtr
@@ -3904,23 +3898,16 @@ nsWindow::OnDragLeave(void)
 
 void
 nsWindow::OnDragEnter(nscoord aX, nscoord aY)
 {
     // XXX Do we want to pass this on only if the event's subwindow is null?
 
     LOGDRAG(("nsWindow::OnDragEnter(%p)\n", (void*)this));
 
-    nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
-
-    if (dragService) {
-        // Make sure that the drag service knows we're now dragging.
-        dragService->StartDragSession();
-    }
-
     nsDragEvent event(PR_TRUE, NS_DRAGDROP_ENTER, this);
 
     event.refPoint.x = aX;
     event.refPoint.y = aY;
 
     nsEventStatus status;
     DispatchEvent(&event, status);
 }
@@ -6098,18 +6085,17 @@ nsWindow::InitDragEvent(nsDragEvent &aEv
     aEvent.isMeta = PR_FALSE; // GTK+ doesn't support the meta key
 }
 
 // This will update the drag action based on the information in the
 // drag context.  Gtk gets this from a combination of the key settings
 // and what the source is offering.
 
 void
-nsWindow::UpdateDragStatus(nsDragEvent   &aEvent,
-                           GdkDragContext *aDragContext,
+nsWindow::UpdateDragStatus(GdkDragContext *aDragContext,
                            nsIDragService *aDragService)
 {
     // default is to do nothing
     int action = nsIDragService::DRAGDROP_ACTION_NONE;
 
     // set the default just in case nothing matches below
     if (aDragContext->actions & GDK_ACTION_DEFAULT)
         action = nsIDragService::DRAGDROP_ACTION_MOVE;
--- a/widget/src/gtk2/nsWindow.h
+++ b/widget/src/gtk2/nsWindow.h
@@ -291,16 +291,21 @@ public:
     void               SetPluginType(PluginType aPluginType);
 #ifdef MOZ_X11
     void               SetNonXEmbedPluginFocus(void);
     void               LoseNonXEmbedPluginFocus(void);
 #endif /* MOZ_X11 */
 
     void               ThemeChanged(void);
 
+    void CheckNeedDragLeaveEnter(nsWindow* aInnerMostWidget,
+                                 nsIDragService* aDragService,
+                                 GdkDragContext *aDragContext,
+                                 nscoord aX, nscoord aY);
+
 #ifdef MOZ_X11
     Window             mOldFocusWindow;
 #endif /* MOZ_X11 */
 
     static guint32     mLastButtonPressTime;
     static guint32     mLastButtonReleaseTime;
 
     NS_IMETHOD         BeginResizeDrag   (nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 aVertical);
@@ -494,18 +499,17 @@ private:
     // full translucency at this time; each pixel is either fully opaque
     // or fully transparent.
     gchar*       mTransparencyBitmap;
  
     // all of our DND stuff
     // this is the last window that had a drag event happen on it.
     static nsWindow    *mLastDragMotionWindow;
     void   InitDragEvent         (nsDragEvent &aEvent);
-    void   UpdateDragStatus      (nsDragEvent &aEvent,
-                                  GdkDragContext *aDragContext,
+    void   UpdateDragStatus      (GdkDragContext *aDragContext,
                                   nsIDragService *aDragService);
 
     // this is everything we need to be able to fire motion events
     // repeatedly
     GtkWidget         *mDragMotionWidget;
     GdkDragContext    *mDragMotionContext;
     gint               mDragMotionX;
     gint               mDragMotionY;